Scala as a better Java

This one is for the Java developers who are curious about Scala. Maybe you have briefly looked at Scala and you were deterred by what at first sight looked like ugly syntax with strange, incomprehensible operators, or you think you have to become a functional programming wizard to understand it.

While the standard library has some methods with names that look like strange operators, you’re not required to use these (for most of them there’s an alternative with a more readable name, such as
foldLeft instead of
/:), and you don’t have to be a functional programming wizard to get benefits from Scala. A good way to get started is to use it as a better Java. In this post I’ll show some examples of how Scala improves upon Java.

You can use == to compare strings

One counter-intuitive feature of Java is the fact that you should normally not use
== to compare strings, because
== means reference equality, and in the case of strings it does not compare the content of two strings.

In Scala,
== is not a built-in operator of the language, it’s just a method that can be overridden. Ofcourse, for class String it compares the content of two strings rather than checking if the two operands refer to the same String object.

Type inference

Java has limited type inference, but in Scala this goes much further. Most of the time you don’t have to specify the type of a value or variable or the return type of a method; the Scala compiler figures out the type automatically from the expression used to initialize the value or variable, or the body of the method. This means that your code will be shorter and easier to read, because there’s less that you have to think about when reading the code.

That said, it’s often a good idea to explicitly specify the return types of methods, because it isn’t always obvious what the return type of a method is.

Case classes

The most well-known pattern in Java is the Java Beans pattern – you write a class with some private fields, getter and setter methods and
equals() and
hashCode() methods if needed. In Java, you need quite a lot of lines of code to write such a simple class.

The getters,
equals() and
hashCode() methods and some other methods (for pattern matching) are automatically generated for a case class.

Pattern matching

Pattern matching is a little bit like a switch statement in Java, but much more powerful. Instead of comparing on a set of values, it can compare if the input matches a more complex pattern. Once you start programming in Scala you’ll discover the many ways in which this is useful, and this blog post is far too short to describe all the possibilities that pattern matching offers.

Scala

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

traitExpr

caseclassNumExpr(value:Double)extendsExpr

caseclassAddExpr(left:Expr,right:Expr)extendsExpr

caseclassSubExpr(left:Expr,right:Expr)extendsExpr

caseclassMulExpr(left:Expr,right:Expr)extendsExpr

caseclassDivExpr(left:Expr,right:Expr)extendsExpr

objectExpressionEvaluatorextendsApp{

// Use pattern matching to recognise different kinds of expressions

// and extract parts out of the expressions

defevaluate(expr:Expr):Double=exprmatch{

caseNumExpr(n)=>n

caseAddExpr(left,right)=>evaluate(left)+evaluate(right)

caseSubExpr(left,right)=>evaluate(left)-evaluate(right)

caseMulExpr(left,right)=>evaluate(left)*evaluate(right)

caseDivExpr(left,right)=>evaluate(left)/evaluate(right)

case_=>sys.error("Unknown type of expression: "+expr)

}

println(evaluate(AddExpr(MulExpr(NumExpr(2.0),NumExpr(3.2)),

SubExpr(NumExpr(2.5),NumExpr(1.0)))))

}

Patterns can be arbitrarily deeply nested; in the evaluate method I could for example have added a case for expressions of a specific form:

Scala

1

2

// Match an expression of the form (e1 * e2) + n

caseAddExpr(MulExpr(e1,e2),NumExpr(n))=>(evaluate(e1)*evaluate(e2))+n

For comprehensions

Scala’s
for expression is much more powerful than Java’s
for statement. You can for example add filters and have nested loops in a single
for expression, leading to shorter and more readable code than the equivalent in Java.

Java

1

2

3

4

5

6

7

8

9

// Java: Find the names of the children of people whose name starts with "A"

List<String>names=newArrayList<>();

for(Personp:persons){

if(p.getName().startsWith("A")){

for(Personc:p.getChildren()){

names.add(c.getName());

}

}

}

Scala

1

2

3

// Scala: Find the names of the children of people whose name starts with "A"

valnames=for(p<-persons ifp.name.startsWith("A");c<-p.children)

yieldc.name

Ofcourse, in Java 8 you could write this in a shorter way using streams, but there would still be a lot more boilerplate than in Scala.

Java

1

2

3

4

5

6

// Java 8: Find the names of the children of people whose name starts with "A"

List<String>names=persons.stream()

.filter(p->p.getName().startsWith("A"))

.flatMap(p->p.getChildren().stream())

.map(Person::getName)

.collect(Collectors.toList());

Scala

1

2

3

// Scala: Do the same with filter, flatMap, map

valnames=persons.filter(p=>p.name.startsWith("A"))

.flatMap(_.children).map(_.name)

Conclusion

In Scala, you need to write a lot less code to do the same thing as in Java, which makes you more productive, not only when writing, but also when reading code. Even if you don’t want to learn about functional programming, Scala’s powerful type system and the many other features that Scala offers, it can still make you more productive.