Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

New Language Features on the JVM

DZone's Guide to

New Language Features on the JVM

Why, after Java has dominated the enterprise landscape for so many years, is there an explosion of new languages and features targeting the JVM? Read on and listen to David Buschman's opinion on the matter.

· Java Zone
Free Resource

Managing a MongoDB deployment? Take a load off and live migrate to MongoDB Atlas, the official automated service, with little to no downtime.

Recently, I have noticed a trend where former Java developers are currently writing code for the JVM but not in Java. Full disclosure, I am one of them. We are using other languages like Scala or Clojure in place of Java.  Even newcomers like Kotlin and Xtend are getting support. So why, after Java has dominated the enterprise landscape for so many years, is there an explosion of new languages and features targeting the JVM. Furthermore, why are Java developers now using these new languages to write their software. Taking some time to look at what these new languages have in common can shed some light on why developers are moving to these new languages to program in.

Functions as Parameters

This has been one of the biggest features missing from Java so a very long time.  All of the new languages make it very clear that this feature is one of the main reason to use their language to write your software with. The consistency of these new languages all keying in on this feature signifies that it is a very important feature for the future.  Even with Java 8, functions as parameters support is a bolt on to the language and is currently limited in 3rd party library usage to date.

    def sayHello(name: String) = s"Hello ${name}"
    def sayGoodbye(name: String) = s"Goodbye ${name}"

    val functions = Seq[String => String](sayHello, sayGoodbye)
    functions
      .map { func => func("DaVe.") }
      .map(println)

    // Produces: 
    // 
    // Hello DaVe.
    // Goodbye DaVe.


High Order Functions (or Lambdas)

Now that we can pass functions as parameters, we can also return them from functions as return types as well. This enables developers to compose functions into more complicated functions and return that function as the returned value. This is a powerful tool that can be used to construct complicated algorithms in very simple ways. Composition can also be used to dynamically build up business logic and delay execution until all the necessary logic is completely assembled.  This can now be done in Java 8 but it is an order of magnitude easier in these new languages. The fact that this feature is a major “bullet point” feature of these almost all of these new languages indicates its importance for developers.

    def plus1(i: Int): Int = i + 1
    def times2(i: Int): Int = i * 2
    def minus1(i: Int): Int = i - 1

    def composed: Int => Int = { i => minus1(times2(plus1(i))) } // ((i + 1) * 2) - 1

    println(composed(5)) //  Produces: (( 5 + 1) * 2) - 1 = 11
    println(composed(10)) // Produces: ((10 + 1) * 2) - 1 = 21


Pattern Matching (or Case Matching)

This is a feature that is worth its weight in gold and a huge code implication. This ability to write compact code to match in type or a value within an object in a very simple easy to understand way is a huge time saver. I will just let a few examples speak for themselves. 

   def pattern(obj: Any): String = obj match {
      case i: Int                    => s"Integer = ${i}"
      case s: String if s.length > 0 => s"String  = ${s}"
      case s: String                 => s"String is empty"
      case l: Long                   => s"Long    = ${l}"
      case unknown                   => s"Unknown value ${unknown}"
    }

    Seq[Any](123, "DaVe.", 456L, "", 0.123).map(pattern).map(println) 
 // Produces:
    // Integer = 123
    // String  = DaVe.
    // Long    = 456
    // String is empty
    // Unknown value 0.123

And: 

   case class Contact(first: String, last: String, email: String)

   def identify(in: Contact): String = in match {
     case Contact("Dave", _, _)     => "Me"
     case Contact(_, "Buschman", _) => "Family Member"
     case Contact(_, _, _)          => "Kids, do not talk to strangers"
   }


Compiler, Write This Code For Me.

Developers now want the compiler to write more code for them so they do not have to. They do not get bogged down in the details of boilerplate code but stay focused on the business logic. Programs, after all, are better at repetitive mundane tasks than humans.  Leaving more of the implementation details for the compiler to get right every time simplifies our job. In Scala, For comprehensions and Macros are good examples onf places where we ask the compiler to generate lots of boilerplate code that we don’t want to be bothered with having to do. NOTE: The case matching examples above also make use of compiler-generated code to implement the requested functionality.

  import play.api.libs.json._

  case class Contact(first: String, last: String, email: String)
  object Contact {
    // Macro = code generated for Contact JSON de/serialization at compile time 
    implicit val _json = Json.format[Contact] // Awesome implicit magic here
  }

  val entity = Contact("Dave", "Buschman", "not@gonna.happen")

  // Serialization 
  val json = Json.toJson[Contact](entity)
  println(json.toString())
  // Produces: {"first":"Dave","last":"Buschman","email":"not@gonna.happen"}

  // Deserialization 
  Json.fromJson[Contact](json) match {
    case JsSuccess(e: Contact, _) => println(s"Full Name is ${e.first} ${e.last}")
    case JsError(errors)          => errors.map(println)
  }
  // Produces: Full Name is Dave Buschman


Language X is Not the Only Language in This Application

Going forward,  developers will not be tied to a specific language but will use different languages for different projects based the project’s needs. Polyglot programming is already here with most developers having and primary language like Java or Scala and secondary languages like Maven XML, SBT, Bash, Go, YAML, and even Dockerfile. We already code in multiple secondary languages, it will not be long before most developers will need to be fluent in multiple primary languages as well. The days of entire systems built in a single “one-size-fits-all” language is coming to a close. As an industry, we have matured to the point where interoperability between languages has become common place and easy to accomplish in our build systems.

   def callJava(in: Option[String]) = System.out.println(in.getOrElse(null))

   callJava(Some("foo")) // Produces: foo 
   callJava(None)        // Produces: null 


Conclusion

Whether you believe these new languages are all hype or the "best thing since sliced bread" these new languages and the features they provide give developers some powerful tools to make their coding tasks faster and easier to accomplish. It is a great time to be a developer with all of the choices we have at our fingertips. 

MongoDB Atlas is the easiest way to run the fastest-growing database for modern applications — no installation, setup, or configuration required. Easily live migrate an existing workload or start with 512MB of storage for free.

Topics:
scala ,jvm ,java ,kotlin

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}