Want to dive even deeper?

Take the course Stairway to Scala Applied I by Bill Venners and Dick Wall and become an expert!
Stairway to Scala Applied I
by Bill Venners , Dick Wall

Check it out!
You're watching a preview of this video, click the button on the left to puchase the full version from Atomikos ExtremeTransactions Certification.

Unsung Heroes: Less Fashionable Patterns in Scala

Monads are the talk of the town, and everyone's doing them. In the virtual monad gold-rush, however, have we lost sight of some of the other useful tips, tricks and patterns that have got us to where we are. In this session I will examine a number of useful code snippets and ideas that I have used successfully on many projects, sometimes alongside monads, to great effect. There may be some useful corner cases you have overlooked, or perhaps just would like a refresher in some of the things you may have discovered but then forgotten.

This talk is suitable for Scala beginners but (I hope) will be of use to more experienced Scala developers as well, even if only as a gentle reminder about some of the tricks used, or perhaps in the effective combinations of some of them that have proven useful over time.


Published on
  • 3.417
  • 35
  • 2
  • 16
  • 1
  • Unsung Heroes Useful, Non-monadic Patterns
  • NoMonads? (NoSQL…) ● Not Only Monads ● Why? ● Why Not? ● Occam’s Razor Refresher
  • Monads ● Incredible, Cosmic Power
  • Why Not? ● Overkill ● Monads Don’t Mix ● Ease of Use ● Pragmatism
  • Occam’s Razor
  • The Three Laws of APIs An API Must Work An API Must be Simple An API Can be Clever, but not at the expense of the first two laws * These rules are also a good basis for all software development IMHO
  • The Mighty, Mighty Case Class // Stringly Typed: def lookUpEmpNo(first: String, last: String, branch: String): Int // Case Classes case class Person(first: String, last: String) case class Branch(name: String) case class Employee(person: Person, employeeNumber: Int) def lookUpEmpNo(person: Person, branch: Branch): Employee
  • And Don’t Forget Case Objects def lookupById(id: String, cache: Boolean, remote: Boolean): (String, String) case class EmployeeId(id: String) sealed abstract class IsCached(cached: Boolean) case object Cached extends IsCached(true) case object NotCached extends IsCached(false) sealed abstract class IsRemote(isRemote: Boolean) case object Local extends IsRemote(false) case object Remote extends IsRemote(true) def lookupById(id: EmployeeId, cache: IsCached, remote: IsRemote): Person
  • Loans def withPrintWriter(fileName: String)(fn: PrintWriter => Unit): Unit = { val printWriter = new PrintWriter(fileName) try { fn(printWriter) } finally printWriter.close() } withPrintWriter("hello.txt") { pw => pw.println("Hello, World!") pw.println("Goodbye Cruel World") }
  • Loans def withIterator[A](fileName: String)(fn: Iterator[String] => A): A={ val source = Source.fromFile(fileName) try { val iter = source.getLines() fn(iter) } finally source.close() } withIterator("hello.txt") { iter => iter.map(_.toUpperCase).toList } res5: List[String] = List(HELLO, WORLD!, GOODBYE CRUEL WORLD)
  • But... withIterator("hello.txt") { iter => iter.map(_.toUpperCase) } java.io.IOException: Bad file descriptor withIterator("hello.txt") { iter => iter } java.io.IOException: Bad file descriptor
  • Type Parameters case class DBQuery[T : JsonFormat : Manifest] (designDoc: String, view: String) object DBQuery { def apply[T : JsonFormat : Manifest](view: String) = { val designDoc = manifest[T].runtimeClass.getName DBQuery(designDoc, view) } }
  • Type Parameters def query[T : JsonFormat](dbQuery: DbQuery[T]): Seq[T] = { val results: Seq[String] = databaseQuery(dbQuery.designDoc, dbQuery.view) results.map(_.toJson.convertTo[T]) } // Because... val personQuery = DbQuery[Person]("allByName") val people = query(personQuery)
  • Generic Pattern Matching case class Doohickey[T](item: T, combinerFn: (T, T) => T) { def combineWith(other: Any): Option[T] = other match { case other: T => Some(combinerFn(item, other)) case _ => None } } warning: abstract type pattern T is unchecked since it is eliminated by erasure case other: T => Some(combinerFn(item, other))
  • Generic Pattern Matching scala> val strDoohickey = Doohickey[String]("Hello ", (x, y) => x+y) strDoohickey: Doohickey[String] = Doohickey(Hello ,<function2>) scala> strDoohickey.combineWith("Mum!") res12: Option[String] = Some(Hello Mum!) scala> strDoohickey.combineWith(3) java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
  • Generic Pattern Matching case class Doohickey[T : ClassTag](item: T, combinerFn: (T,T) => T) { def combineWith(other: Any): Option[T] = other match { case other: T => Some(combinerFn(item, other)) case _ => None } } scala> strDoohickey.combineWith("Mum!") res15: Option[String] = Some(Hello Mum!) scala> strDoohickey.combineWith(8)
  • Generic Pattern Matching def isAListOf[T](x: Any)(implicit ct: ClassTag[T]) = x match { case Nil => "No, this is an empty list" case yes: List[T] if yes.head.getClass == ct.runtimeClass => s"Yes, $yes is a list of ${ct.runtimeClass.getName}" case _ => "No, this is a list of something else" } scala> isAListOf[String](List("hi", "there")) res19: String = Yes, List(hi, there) is a list of java.lang.String scala> isAListOf[String](List(1, 2)) res20: String = No, this is a list of something else
  • Types Again case class StringList(items: List[String]) case class IntList(items: List[Int]) def isAListOfStringOrInt(x: Any) = x match { case StringList(strings) => strings.map(_.toUpperCase).mkString case IntList(ints) => ints.sum.toString } scala> res23: scala> res25: isAListOfStringOrInt(IntList(List(1,2,3))) String = 6 isAListOfStringOrInt(StringList(List("hello", "mum"))) String = HELLOMUM
  • Immutable Builder case class Credentials(user: String, pass: String) case class HttpConnection(server: String, port: Int = 80, ssl: Boolean = false, creds: Option[Credentials] = None) HttpConnection("www.slashdot.org") HttpConnection(server = "localhost", port = 8443, ssl = true, creds = Some(Credentials(user = "dick", pass = "s3curep@ssw0rd")))
  • Immutable Builder case class DefinedSNP(name: String, location: Int, alleles: Set[Char]) case class NamedLocatedSNP(name: String, location: Int) { def alleles(alleles: String) = DefinedSNP(name, location, alleles.toSet) } case class NamedSNP(name: String) { def location(location: Int) = NamedLocatedSNP(name, location) } case object SNP { def named(name: String) = NamedSNP(name) } val theSnp = SNP named "HLA23*" location 1211243 alleles "ATG" theSnp: DefinedSNP = DefinedSNP(HLA23*,1211243,Set(A, T, G))
  • Type Classes import spray.json._ import DefaultJsonProtocol._ case class Color(name: String, red: Int, green: Int, blue: Int) implicit val colorFormat = jsonFormat4(Color) val color = Color("CadetBlue", 95, 158, 160) def printJson[JF : JsonFormat](json: JF): Unit = { val jsonFormat = implicitly[JsonFormat[JF]] // or use implicit parameter println (jsonFormat.write(json)) } printJson(color) {"name":"CadetBlue","red":95,"green":158,"blue":160}
  • State Machine Builders case class DBQuery(designDoc: String, view: String, params: Map[String, JsValue]) { def addParam[JS : JsonWriter](key: String, value: JS) = { val newParams = this.params + (key -> value.toJson) copy(params = newParams) } def reduce(reduce: Boolean): DBQuery = if (reduce) { val newParams = ((params - "group") - "include_docs") + ("reduce" -> reduce.toJson) copy(params = newParams) } else addParam("reduce", reduce) def startKey[JS : JsonWriter](startKey: JS) def endKey[JS : JsonWriter](endKey: JS) def key[JS : JsonWriter](key: JS) def keys[JS : JsonWriter](keys: Seq[JS]) //... } = = = = addParam("startkey", startKey) addParam("endkey", endKey) addParam("key", key) addParam("keys", keys.map(_.toJson).toList)
  • Case with Paired Type Class Companion sealed abstract class AbstractDBObject[O : Manifest] extends JsonFormat[O] { val typeManifest = manifest[O] } def getJson[T : AbstractDBObject](item: T): JsValue = { val dbObjCompanion = implicitly[AbstractDBObject[T]] println("Item manifest " + dbObjCompanion.typeManifest) dbObjCompanion.write(item) }
  • Case with Paired Type Class Companion abstract class DBObject2[T1 : JsonFormat, T2 : JsonFormat, O extends AbstractDBObject[O]{ : Manifest] def apply(v1:T1,v2:T2):O def unapply(o:O):Option[(T1,T2)] implicit val jsonFormat = this def write(o: O): JsValue = { unapply(o) match { case Some((v1, v2)) => JsArray(List(v1.toJson, v2.toJson)) } } def read(value: JsValue): O = ??? // implement here in terms of apply }
  • Case with Paired Type Class Companion case class Person(name: String, age: Int) object Person extends DBObject2[String, Int, Person] def getJson[T : AbstractDBObject](item: T): JsValue = { val dbObjCompanion = implicitly[AbstractDBObject[T]] println("Item manifest " + dbObjCompanion.typeManifest) dbObjCompanion.write(item) } scala> val person = Person("Harry Potter", 27) person: Person = Person(Harry Potter,27) scala> getJson(person) Item manifest $line20.$read$$iw$$iw$$iw$$iw$$iw$$iw$Person res0: spray.json.JsValue = ["Harry Potter",27]
  • Tagged Types type Tagged[U] = { type Tag = U } type @@[T, U] = T with Tagged[U] sealed trait KiloGram def KiloGram[A](a: A): A @@ KiloGram = a.asInstanceOf[A @@ KiloGram] val mass = KiloGram(20.0) mass: @@[Double,KiloGram] = 20.0 2 * mass res1: Double = 40.0
  • Constructor Function Loans class NewBindingModule(fn: MutableBindingModule => Unit) extends BindingModule with Serializable { lazy val bindings = { val module = new Object with MutableBindingModule fn(module) module.freeze().fixed.bindings } } object NewBindingModule { def newBindingModule(fn: MutableBindingModule => Unit): BindingModule = new NewBindingModule(fn) }
  • Constructor Function Loans implicit val bindingModule = newBindingModule { module => import module._ bind [DBLookup] toProvider { module => new MySQLLookup(module) } bind [WebService] to newInstanceOf [RealWebService] bind [Int] idBy 'maxPoolSize toSingle 10 bind [QueryService] toSingle { new SlowInitQueryService } }
  • Parfait trait Db { def name: String } class MySQLDb extends Db { val name = "MySQL" } class PostgresDb extends Db { val name = "Postgres" }
  • Parfait trait WeatherWS { def currentTemp: Double } class ForecastIOWeatherWS extends WeatherWS { def currentTemp = 101.5 } class WeatherDotComWeatherWS extends WeatherWS { def currentTemp = 99.7 }
  • Parfait trait DbConfig { val db: Db } trait WeatherWSConfig { val weather: WeatherWS } trait WholeSystemConfig extends DbConfig with WeatherWSConfig
  • Parfait class DbDoer(implicit config: DbConfig) { val myDbName = config.db.name def getDbName: String = myDbName } class WeatherDoer(implicit config: WeatherWSConfig) { def getCurrentTemp: Double = config.weather.currentTemp } trait TempDoubler { def db: Db // pure abstract - must be provided by implementing class def weather: WeatherWS // likewise // alternatively, def wholeSystemConfig: WholeSystemConfig lazy val getIt: String = s"${db.name} x ${weather.currentTemp * 2}" // still need care with trait init - use lazy }
  • Parfait class TotalSystem(systemName: String)(implicit val config: WholeSystemConfig) extends TempDoubler { val db = config.db val weather = config.weather val dbThing = new DbDoer // implicitly injected with the config for Db val wsThing = new WeatherDoer // ditto, but different config type - WeatherWS def getBoth: String = s"System is $systemName, Db is ${dbThing.getDbName} and temperature is ${wsThing.getCurrentTemp}" val doubleTempAndDB: String = getIt }
  • Parfait class DbWeatherTest extends FunSpec with Matchers { describe ("Using the implicit parameter injection approach") { it ("should work for MySQL and Forecast.io") { implicit object MySQLForecastConfig extends WholeSystemConfig { val db: Db = new MySQLDb val weather: WeatherWS = new ForecastIOWeatherWS } val system = new TotalSystem("Test system 1") system.getBoth should be ("System is Test system 1, Db is MySQL and temperature is 101.5") }
  • Parfait it ("should work for Postgres and Weather.com") { implicit object MySQLForecastConfig extends WholeSystemConfig { val db: Db = new PostgresDb val weather: WeatherWS = new WeatherDotComWeatherWS } val system = new TotalSystem("Test system 2") system.getBoth should be ("System is Test system 2, Db is Postgres and temperature is 99.7") system.doubleTempAndDB should be ("Postgres x 199.4") } } }
  • Q&A ● If there’s time...
  • Tagged Types type Tagged[U] = { type Tag = U } type @@[T, U] = T with Tagged[U] sealed trait KiloGram def KiloGram[A](a: A): A @@ KiloGram = a.asInstanceOf[A @@ KiloGram] val mass = KiloGram(20.0) mass: @@[Double,KiloGram] = 20.0 2 * mass res1: Double = 40.0
Thumbnail for: Findings Revealed: 2015 State of the Software Supply Chain

Findings Revealed: 2015 State of the Software Supply Chain

WaiMan Yau

free
Thumbnail for: Web Application Security Reloaded for the HTML5 era

Web Application Security Reloaded for the HTML5 era

Carlo Bonamico

free
Thumbnail for: Gimme Caching - The Distributed JCache(JSR107) Way

Gimme Caching - The Distributed JCache(JSR107) Way

David Brimley

free
Thumbnail for: Never mind the bollocks: here's the Linux containers

Never mind the bollocks: here's the Linux containers

Patrick Chanezon

free
Thumbnail for: How to lower the power consumption of your app, without affecting performance

How to lower the power consumption of your app, without affecting performance

Rick Schwartz

free
Thumbnail for: NOW TV and Linear Streaming: The unpredictable scalability challenge

NOW TV and Linear Streaming: The unpredictable scalability challenge

Tom Maule

free
Thumbnail for: The end of server management : hosting has to become a commodity

The end of server management : hosting has to become a commodity

Quentin ADAM

free
Thumbnail for: The Future of Personal Robotics

The Future of Personal Robotics

Nicolas Rigaud

free
Thumbnail for: Performance Tuning, Top 10 Your Doing it Wrong!

Performance Tuning, Top 10 Your Doing it Wrong!

Kirk Pepperdine

free
Thumbnail for: Let’s Get to the Rapids: Java 8 Stream Perfomance

Let’s Get to the Rapids: Java 8 Stream Perfomance

Maurice Naftalin

free
Thumbnail for: Pushing The Limits With Java Enterprise Cloud Development

Pushing The Limits With Java Enterprise Cloud Development

Simon Ritter

free
Thumbnail for: JCP, Adopt-a-JSR & You

JCP, Adopt-a-JSR & You

Heather VanCura

free
Thumbnail for: 3 Keys to Rapid Deployment Success

3 Keys to Rapid Deployment Success

Sven Erik Knop

free
Thumbnail for: Bringing IBM Watson to the Cloud

Bringing IBM Watson to the Cloud

Dale Lane

free
Thumbnail for: The Smartwatch Revolution begins: Developing for Android Wear

The Smartwatch Revolution begins: Developing for Android Wear

Pratik Patel

free
Thumbnail for: The Google Cloud Plaform - Beyond simple use cases

The Google Cloud Plaform - Beyond simple use cases

David Gageot

free
Thumbnail for: The Cloud, an Arduino, an Application, Server, and me - Adventures In and Out of the Cloud

The Cloud, an Arduino, an Application, Server, and me - Adventures In and Out of the Cloud

Holly Cummins

free
Thumbnail for: TestOps - Chasing the White Whale

TestOps - Chasing the White Whale

Ioana Serban

free
Thumbnail for: Experimenting with ServiceWorker

Experimenting with ServiceWorker

Sandro Paganotti

free
Thumbnail for: Accessibility and how to get the most from your screenreader

Accessibility and how to get the most from your screenreader

Edd Sowden

free
Thumbnail for: What Were You Doing In 1995? A 20 Year Retrospective of Java

What Were You Doing In 1995? A 20 Year Retrospective of Java

Simon Ritter , Steve Elliott

free
Thumbnail for: SQL’s back: querying document databases the old fashioned way

SQL’s back: querying document databases the old fashioned way

Matthew Revell

free
Thumbnail for: Decoding the air around you with Java and $7 hardware

Decoding the air around you with Java and $7 hardware

Bert Jan Schrijver

free
Thumbnail for: "Catch me if you can" - Java on wearables

"Catch me if you can" - Java on wearables

Gerrit Grunwald

free
Thumbnail for: Miniboxing: Fast Generics for Primitive Types

Miniboxing: Fast Generics for Primitive Types

Vlad Ureche

free
Thumbnail for: goto java;

goto java;

Martin Skarsaune

free
Thumbnail for: Not my department?! How our privacy is broken and what you can do about it.

Not my department?! How our privacy is broken and what you can do about it.

Anna Biselli

free
Thumbnail for: Java 8 in Anger

Java 8 in Anger

Trisha Gee

free
Thumbnail for: The Hidden Gems of PDF

The Hidden Gems of PDF

Michaël Demey

free
Thumbnail for: Design Patterns in the 21st Century

Design Patterns in the 21st Century

Samir Talwar

free
Thumbnail for: Keynote: The Extraordinary Team of Developers

Keynote: The Extraordinary Team of Developers

Trisha Gee , Daniel Bryant

free
Thumbnail for: Java Generics: Past, Present and Future

Java Generics: Past, Present and Future

Richard Warburton , Raoul-Gabriel Urma

free
Thumbnail for: Building securely with agile

Building securely with agile

Michael Brunton-spall

free
Thumbnail for: STOP BREAKING MY STUFF

STOP BREAKING MY STUFF

Katharine Fitzpatrick

free
Thumbnail for: All Change! How the new economics of Cloud will make you think differently about Java

All Change! How the new economics of Cloud will make you think differently about Java

Steve Poole

free
Thumbnail for: Powering real-time web apps with Hazelcast

Powering real-time web apps with Hazelcast

Andrejs Jermakovics

free
Thumbnail for: What is your build telling you about your application structure?

What is your build telling you about your application structure?

Abraham Marin-Perez

free
Thumbnail for: Practical Challenges of moving from CI to CD using Maven

Practical Challenges of moving from CI to CD using Maven

Jatin Bhadra

free
Thumbnail for: Destination: Cloud. Deploying Applications To The Cloud With Docker

Destination: Cloud. Deploying Applications To The Cloud With Docker

Ryan Baxter

free
Thumbnail for: Finally, Security API JSR 375

Finally, Security API JSR 375

Alex Kosowski

free
Thumbnail for: Level up your Android Build

Level up your Android Build

Volker Leck

free
Thumbnail for: Practical Continuous Deployment

Practical Continuous Deployment

Steve Smith

free
Thumbnail for: Nuts and Bolts of WebSocket

Nuts and Bolts of WebSocket

Arun Gupta

free
Thumbnail for: The Seven Deadly Sins of Microservices

The Seven Deadly Sins of Microservices

Daniel Bryant

free
Thumbnail for: Making Events for Local Dev Communities

Making Events for Local Dev Communities

Celestino Bellone , Federico Yankelevich

free
Thumbnail for: Developing iOS applications with Java and Eclipse

Developing iOS applications with Java and Eclipse

Grant Ronald

free
Thumbnail for: Welcome Keynote

Welcome Keynote

Mark Hazell

free
Thumbnail for: Refactor your Java EE application using Microservices and Containers

Refactor your Java EE application using Microservices and Containers

Arun Gupta

free
Thumbnail for: The Dark arts of building your own framework

The Dark arts of building your own framework

Andrey Glaschenko , Konstantin Krivopustov

free
Thumbnail for: Java EE 8, a snapshot overview

Java EE 8, a snapshot overview

David Delabassee

free
Thumbnail for: Programming at any Scale

Programming at any Scale

Andrew Harmel-Law

free
Thumbnail for: Java is dead, long live Ceylon, Kotlin,…

Java is dead, long live Ceylon, Kotlin,…

Russel Winder

free
Thumbnail for: Java EE changes design pattern implementation

Java EE changes design pattern implementation

Alex Theedom

free
Thumbnail for: From 0 to 60 million users: Scaling for speed and high availability

From 0 to 60 million users: Scaling for speed and high availability

Aviran Mordo

free
Thumbnail for: Android Testing: A New Hope

Android Testing: A New Hope

Zan Markan , Nicholas Jackson

free
Thumbnail for: Building Cloud Powered Android Apps with Azure

Building Cloud Powered Android Apps with Azure

Chris Risner

free
Thumbnail for: HTTP/2 comes to Java. What Servlet 4.0 means to You

HTTP/2 comes to Java. What Servlet 4.0 means to You

David Delabassee

free
Thumbnail for: 50 minutes to develop a full Java EE application with Forge? Is that all?

50 minutes to develop a full Java EE application with Forge? Is that all?

Antonio Goncalves

free
Thumbnail for: How to Rock your Web Apps with Spring and Vaadin

How to Rock your Web Apps with Spring and Vaadin

Sami Ekblad

free
Thumbnail for: In-Memory Computing - Distributed Systems

In-Memory Computing - Distributed Systems

Christoph Engelbert

free
Thumbnail for: 5 reasons why developers should pay attention to robotics

5 reasons why developers should pay attention to robotics

Nicolas Rigaud

free
Thumbnail for: Ceylon from here to infinity: the big picture and what's coming

Ceylon from here to infinity: the big picture and what's coming

Stephane Epardaud

free
Thumbnail for: Is your profiler speaking the same language as you?

Is your profiler speaking the same language as you?

Simon Maple

free
Thumbnail for: Java 9: Make Way for Modules!

Java 9: Make Way for Modules!

Mark Reinhold

free
Thumbnail for: Comparing different concurrency models on the JVM

Comparing different concurrency models on the JVM

Mario Fusco

free
Thumbnail for: The 10 Golden Rules of Mobile UX

The 10 Golden Rules of Mobile UX

Emilia Ciardi

free
Thumbnail for: Ludicrously Fast Builds with Buck

Ludicrously Fast Builds with Buck

Simon Stewart

free
Thumbnail for: Akka Streams with Scala and Java

Akka Streams with Scala and Java

Jamie Allen

free
Thumbnail for: Diversity Rules!

Diversity Rules!

Amali de Alwis

free
Thumbnail for: Making Enterprise Java Architecture Sustainable

Making Enterprise Java Architecture Sustainable

Markus Eisele

free
Thumbnail for: Combining R with Java for Data Analysis

Combining R with Java for Data Analysis

Ryan Cuprak , Elsa Cuprak

free
Thumbnail for: Microservices Made Easy with Spring Cloud and Netflix OSS

Microservices Made Easy with Spring Cloud and Netflix OSS

David Syer

free
Thumbnail for: Flyway - Database Migration made easy

Flyway - Database Migration made easy

Axel Fontaine

free
Thumbnail for: CDI 2.0: what is in the work?

CDI 2.0: what is in the work?

Antoine Sabot-Durand , José Paumard

free
Thumbnail for: Functional patterns for scala beginners

Functional patterns for scala beginners

Clément Delafargue

free
Thumbnail for: WildFly 9

WildFly 9

Kabir Khan

free
Thumbnail for: Let’s Get to the Rapids: Java 8 Stream Perfomance

Let’s Get to the Rapids: Java 8 Stream Perfomance

Maurice Naftalin

free
Thumbnail for: From Requirements to Deployment: Implementing a Microservice in Java using BDD and TDD

From Requirements to Deployment: Implementing a Microservice in Java using BDD and TDD

John Ferguson Smart

free
Thumbnail for: Level Up your Dev Skills with Static Analysis

Level Up your Dev Skills with Static Analysis

David Lindsay

free
Thumbnail for: Devoxx4Kids

Devoxx4Kids

Dan Hardiker

free
Thumbnail for: Software Architecture as Code

Software Architecture as Code

Simon Brown

free
Thumbnail for: Top 10 Real-life WebSocket Use Cases and Experiences

Top 10 Real-life WebSocket Use Cases and Experiences

Richard Cullen

free
Thumbnail for: Predicting the Future with Machine Learning

Predicting the Future with Machine Learning

Amy Nicholson

free
Thumbnail for: One Framework, No Dependencies: Using Frameworks to Avoid Common Pitfalls of App Development

One Framework, No Dependencies: Using Frameworks to Avoid Common Pitfalls of App Development

Lee Boonstra

free
Thumbnail for: The First IoT JSR: Units of Measurement

The First IoT JSR: Units of Measurement

Leonardo Lima , Chris Senior

free
Thumbnail for: Never Mind the Devoxx

Never Mind the Devoxx

David Blevins

free
Thumbnail for: Five Ways to Not Suck at Being a Java Freelancer

Five Ways to Not Suck at Being a Java Freelancer

Roberto Cortez

free
Thumbnail for: Building the UKs biggest IoT network

Building the UKs biggest IoT network

Romanas Sonkinas

free
Thumbnail for: Java EE Game Changers

Java EE Game Changers

David Blevins

free
Thumbnail for: Express yourself with Java 8

Express yourself with Java 8

Benjamin Weber

free