Scala as Concise Java

Java code often has a lot of boilerplate code—getters, setters, access modifiers, code to deal with checked exceptions…. The growing list bloats the code. As you’ll see here, the Scala compiler walks a few extra miles so you don’t have to expend efforts to write and maintain code that can be generated.

Less Boilerplate

Scala has very high code density—you type less to achieve more. To contrast, let’s start with an example of Java code:

FromJavaToScala/Greetings.java
 
//Java code
 
public​ ​class​ Greetings {
 
public​ ​static​ ​void​ main(​String​​[]​ args) {
 
for​(​int​ i = 1; i < 4; i++) {
 
System​.out.print(i + ​","​);
 
}
 
System​.out.println(​"Scala Rocks!!!"​);
 
}
 
}

Here’s the output:

 
1,2,3,Scala Rocks!!!

Scala makes quite a few things in this code optional. First, it does not care whether you use semicolons. Second, there’s no real benefit for the code to live within the class Greetings in a simple example like this, so you can get rid of that. Third, there’s no need to specify the type of the variable i. Scala is smart enough to infer that i is an integer. Finally, you can use println without the System.out. prefix. Here’s the Java code simplified to Scala:

FromJavaToScala/Greet.scala
 
for​ (i <- 1 to 3) {
 
print(s​"$i,"​)
 
}
 
 
println(​"Scala Rocks!!!"​)

To run this script, type scala Greet.scala on the command line, or run it from within your IDE.

You should see this output:

 
1,2,3,Scala Rocks!!!

Rather than concatenating the print message using the + operator, we used string interpolation (using the syntax s"…${expression}…"), which makes code more expressive and concise—we’ll discuss string interpolation in String Interpolation.

Scala’s loop structure is pretty lightweight. We simply indicated that the value of the index i goes from 1 to 3. The left of the arrow (<-) defines a val and its right side is a generator expression. On each iteration, a new val is created and initialized with a consecutive element from the generated values.

Scala reduces boilerplate code. It offers some syntactical conveniences too.

More Convenience

In the previous code we used a val. You can define a variable using either a val or a var. The variables defined using val are immutable and can’t be changed after initialization. Those defined using var—aka keyword of shame—however, are mutable and can be changed any number of times.

The immutability applies to the variable and not the instance to which the variable refers. For example, if we write val buffer = new StringBuffer(), we can’t change what buffer refers to. However, we can modify the state of the referred instance using StringBuffer’s methods like append. Don’t assume that an object with only val references is entirely immutable.

On the other hand, if we define an instance of an immutable class like String using, for example, val str = "hello", then we can modify neither the reference nor the state of the referred instance.

You can make an instance of a class immutable by defining all of its fields using val and providing only methods that allow reads and not changes to the state of the instance.

In Scala, prefer val over var as much as possible since that promotes immutability, which leads to fewer errors, and functional style.

In the Greet.scala code, the range that was generated included both the lower bound (1) and the upper bound (3). You can exclude the upper bound from the range via the until method instead of the to method:

FromJavaToScala/GreetExclusiveUpper.scala
 
for​ (i <- 1 until 3) {
 
print(s​"$i,"​)
 
}
 
 
println(​"Scala Rocks!!!"​)

Run the code to see this output:

 
1,2,Scala Rocks!!!

It’s easy to miss that to is a method. to and until are actually methods on RichInt—we’ll discuss rich wrappers in Scala Classes for Java Primitives. The variable i, which is of type Int, is implicitly converted to RichInt so this method could be called on the variable. These two methods return an instance of Range. So, calling 1 to 3 is equivalent to 1.to(3), but the former is more elegant.

In Scala you can drop both the dot and the parentheses if a method takes either zero or one parameter. If a method takes more than one parameter, you must use the parentheses, but the dot is still optional.

We already saw a benefit of this flexibility: a + b is really a.+(b), and 1 to 3 is really 1.to(3).

You can take advantage of this lightweight syntax to create code that reads fluently. For example, assume we have a turn method defined on a class Car:

 
def​ turn(direction: ​String​) ​//...

We can call the previous method in a lightweight syntax as follows:

 
car turn ​"right"

By dropping the dots and parentheses you can reduce noise in code.

In the previous example, it appears that we’ve reassigned i as we iterated through the loop. However, i is not a var; it is a val. Each time through the loop we’re creating a different val named i. We can’t inadvertently change the value of i within the loop because i is immutable. Quietly, we’ve already taken a step toward functional style here; let’s take it further.

Leaning Toward Functional Style

We can also perform the loop in a more functional style using foreach:

FromJavaToScala/GreetForEach.scala
 
(1 to 3).foreach(i => print(s​"$i,"​))
 
 
println(​"Scala Rocks!!!"​)

Here’s the output:

 
1,2,3,Scala Rocks!!!

The previous example is concise, and there are no assignments. We used the foreach method of the Range class. This method accepts a function value as a parameter. So, within the parentheses, we’re providing a body of code that takes one argument, named in this example as i. The => separates the parameter list on the left from the implementation on the right.

Scala infers types and is fully object-oriented, but it does not deal separately with primitives. This leads to a consistent handling of all data types; however, Scala does this without compromising performance.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.104.109