7 Scala features that surprise Java developers
When you know Java, it isn’t that hard to start programming in Scala. Everything you know about object-oriented programming in Java also applies to Scala. Ofcourse Scala is not just Java with a less verbose syntax; it also has a number of features that Java lacks, such as functional programming features and a more powerful type system.
This post is about features that exist in both Java and Scala, but that are implemented in a different way in Scala, which might surprise you as a Java developer as you are learning Scala.
1. Import statements can be anywhere
In Java, import statements must be at the top of the source file, immediately after the package statement. In Scala, you can put import statements almost everywhere. You can for example put an import statement inside the body of a class or method. The scope of the import will be limited in the same way as the scope of members of the class or local variables inside a method (from the point of the import statement to the end of the enclosing block).
For wildcard imports, you use _ (underscore) in Scala instead of * (asterisk) that you would use in Java.
// Import everything from the package scala.concurrent import scala.concurrent._
You can import multiple, specific members in one import statement. In Java you would have to use two separate import statements for this.
// Import math.sin and math.cos import math.{sin, cos}
Scala has no static imports (because static doesn’t exist in Scala), but you can import members of an object with a regular import statement. The example above already shows this, where we import the methods sin and cos from the package object named math. The snippet above is equivalent to the following in Java:
import static java.lang.Math.sin; import static java.lang.Math.cos;
You can rename imported members, so that you can avoid namespace collisions.
// Import scala.collection.mutable.Map as MutableMap import scala.collection.mutable.{Map => MutableMap}
You can exclude specific members, for example when importing everything from a package using a wildcard.
// Import everything from scala.concurrent, but hide JavaConversions import scala.concurrent.{JavaConversions => _, _}
2. Operators are just methods
When you have taken some first steps with Scala’s collection classes you might have thought that Scala must have operator overloading and a way to define custom operators, since for example class List has many members that look like operators: you can use :: to prepend an element to a List, ++ to append two lists, etc.
In fact, Scala doesn’t have operator overloading; it even doesn’t have operators at all. All those things that look like operators, including the regular arithmetic operators that you use on numbers, are really just methods. Method names (really, names for anything, including variables, classes and traits) are not limited to letters and numbers. In addition to that, there’s a special, alternative syntax for calling methods that take one parameter, the infix syntax, so that it looks like you are applying an operator. This works with any method that takes one parameter, not just methods that have operator-like names.
val a = 23 val b = 65 // + is a method in class Int, which can be called using // the regular method call syntax... val sum1 = a.+(b) // ... or using the infix syntax val sum2 = a + b // You can use infix syntax with any method that takes one parameter val result = List(2, 5, 13, 8) contains 4
There’s one special case when using infix syntax: if the method name ends with a : (colon), then the call is right associative, which means the method is called on the right argument with the expression on the left as the argument, instead of the other way around.
val list = List(2, 5, 13, 8) // This means: list.+:(4) rather than 4.+:(list) val result = 4 +: list
Another consequence of the fact that operators are just methods is that they can be overridden just like methods, which means for example that you can use == to compare strings.
3. Everything looks like an object
In Scala, everything looks like an object. Note that I’m not saying that everything is an object, because that’s not the case. The difference between primitive types and reference types still exists, but Scala hides it for the most part.
For example, class Int corresponds to the JVM’s primitive type int, but it looks just like a class with methods, and integer literals behave like they are instances of class Int – you can call methods on them. This makes Scala syntax more uniform than Java, where the way you work with primitive types is different than with reference types.
4. Methods can have multiple parameter lists
In Java, a method always has one parameter list, with zero or more parameters. In Scala, a method can have multiple parameter lists, or even no parameter list at all.
This is useful for partial function application (see also: currying), a functional programming concept. Partial function application means that you fill in one or more parameters (but not all of the parameters) of a function, yielding a new function that you can call with the remaining parameters.
// A method with two parameter lists def add(x: Int)(y: Int) = x + y // The method add2 has no parameter list; it fills in // only the first parameter list of the method add def add2 = add(2) _ // Call add2, which returns a function that takes one parameter, // then call that function with the argument 3 val result = add2(3)
In Scala this often used to pass implicit arguments, which are arguments that you don’t have to explicitly provide when you call a method – Scala automatically looks for a value in the current scope that can be passed as the implicit argument.
Implicit arguments are another powerful Scala feature that also has some drawbacks – they can make code harder to understand because it’s not always obvious what is being passed as the implicit argument.
5. You can define methods inside methods
You often want to avoid methods getting too large, so you split them up into smaller methods. In Java, methods are always defined at class level, which means that any method in the class can access them – even if they are helper methods that are meant to be used only by one specific method. In Scala, you can define methods inside methods, which is useful to hide helper methods from other code.
def sum(xs: List[Int]): Int = { // Nested helper method def helper(accu: Int, rest: List[Int]): Int = rest match { case Nil => accu case _ => helper(accu + rest.head, rest.tail) } // Call the nested helper method helper(0, xs) }
6. The body of the class is the constructor
One thing that confused me when I was first learning Scala, and which wasn’t clearly explained in the books and tutorials I was reading, is that the body of a Scala class is the constructor. In Java you can’t put arbitrary statements in the body of a class; in Scala you can, and they are executed when you create a new instance of the class. Also, you specify the arguments of the constructor in the class declaration line, and the constructor arguments are accessible in all of the methods defined in the class.
class Hello(name: String) { // Statement executed as part of the constructor println("New instance with name: " + name) // Method which accesses the constructor argument def sayHello = println("Hello, " + name + "!") }
The equivalent Java class would look like this:
public class Hello { private final String name; public Hello(String name) { System.out.println("New instance with name: " + name); this.name = name; } public void sayHello() { System.out.println("Hello, " + name + "!"); } }
7. Objects instead of static methods
In Scala, static doesn’t exist. You cannot add static methods to classes. Instead, you can define objects. When you define an object with the same name as a class, then that object is the companion object of that class.
Methods that you define in the companion object of a class are like static methods of a class in Java.
class Hello(name: String) { def sayHello = println("Hello, " + name + "!") } // Companion object of class Hello object Hello { // Factory method def apply(name: String) = new Hello(name) }
The equivalent class in Java would look like this:
public class Hello { private final String name; public Hello(String name) { this.name = name; } public void sayHello() { System.out.println("Hello, " + name + "!"); } public static Hello apply(String name) { return new Hello(name); } }
The apply method is treated in a special way by Scala; there’s a special shortcut syntax to call it.
// This is the regular way to call a method val hello1 = Hello.apply("World") // This is the special shortcut syntax, which is equivalent to the above val hello2 = Hello("World")
Note that this only works with the apply method, not with any other method. The Scala compiler just treats methods named apply in this special way.
Conclusion
I hope this was useful for you if you’re learning Scala as a Java developer. Have fun learning Scala!
In section 4, I think you might be confusing currying with partial application. Currying is the process of going from a single parameter list with multiple parameters to multiple parameter lists with single parameters. Partial application is what you’re doing on line 5 of the code example; the function is already curried.
Thanks for commenting and I think you’re right, I’ve edited that section.
Hi I have one question regarding future scope of the language. Does Scala has a bright future programming language , Or it just sneaking for some period of time ?
In the past few years more and more companies are picking up Scala and using it for real projects and there is a lot of interest for it on developer conferences. It’s definitely here to stay, and in my opinion if you’re a Java developer and you want to learn something new, it’s definitely worth it to have a look at Scala. Not just because you’ll learn a new programming language, it will also make you a better Java developer, because you’ll learn concepts and techniques, such as functional programming, that will be useful no matter what programming language you use.
For big data analytics python is comfortable so can we replace python with scala ?
Is there library support available for the same?
I think pattern matching, futures, the collections API, case classes and immutability are huge wins when moving to Scala, most of the features talked about in this article are syntactic differences that allow for more concise code but there are also many other features that sit above the syntax alone that make Scala a more productive language to work with.
Hi Rama, thanks for your comment. Ofcourse there are many more Scala features that make it an interesting programming language than the things I mentioned in this article. Have a look at my presentation “Practical Scala for the busy Java developer” in which I present more Scala features: https://youtu.be/_Mshtm-SwWs