Programming in Scala as a “Better” Java

Brief introduction to the Scala language for Java programmers

Scala is a programming language for the JVM born in 2004 that is both object oriented and functional. Since it runs in the JVM it can call any Java method and be called by any Java method. So, moving from Java to Scala is practically pain free, all you have to do is learn the new syntax. You have all the Java libraries at your disposal plus all the improvements Scala has to offer. Even though Scala is both OOP and Functional it doesn’t force you to use either of the two paradigms and so it can just be used as a simple OOP replacement for Java with great benefits to speed of coding and readability. In this article I will not get into the details but just show you enough to make you curious and try it. If you want to dive deeper here is a link for you: https://www.scala-lang.org

Here are a few reasons why I think you should start coding in
Scala instead of Java.

Boilerplate / Verbosity

Here is a short list of features of Scala that reduce the verbosity of the code compared to Java

  • A toString method is included automatically in every class. Most of the time it’s human readable.
  • Automatic get/set methods in every class
  • The fields of a class are declared at the top of the class declaration as if they were parameters to the class
  • The method println() instead of System.out.println().
  • No need for return, the last expression in a block is its return value
  • No need to specify public
  • No need for break; in switch/match statements
  • In some cases parentheses are optional
  • If the function is only one line you don’t need to put braces around it

Case Classes

Case classes are just another way to do away with boilerplate code. Most of the time a case class is just a one liner whereas to write the same functionality in Java would take at least 50 lines for a simple class with 2 fields.

<span>case</span> <span>class</span> <span>Person</span><span>(</span><span>name</span><span>:</span> <span>String</span><span>,</span> <span>address</span><span>:</span> <span>String</span><span>)</span>
<span>case</span> <span>class</span> <span>Person</span><span>(</span><span>name</span><span>:</span> <span>String</span><span>,</span> <span>address</span><span>:</span> <span>String</span><span>)</span>
case class Person(name: String, address: String)

Enter fullscreen mode Exit fullscreen mode

<span>public</span> <span>class</span> <span>Person</span> <span>{</span>
<span>private</span> <span>final</span> <span>String</span> <span>name</span><span>;</span>
<span>private</span> <span>final</span> <span>String</span> <span>address</span><span>;</span>
<span>public</span> <span>Person</span><span>(</span><span>String</span> <span>name</span><span>,</span> <span>String</span> <span>address</span><span>)</span> <span>{</span>
<span>this</span><span>.</span><span>name</span> <span>=</span> <span>name</span><span>;</span>
<span>this</span><span>.</span><span>address</span> <span>=</span> <span>address</span><span>;</span>
<span>}</span>
<span>@Override</span>
<span>public</span> <span>int</span> <span>hashCode</span><span>()</span> <span>{</span>
<span>return</span> <span>Objects</span><span>.</span><span>hash</span><span>(</span><span>name</span><span>,</span> <span>address</span><span>);</span>
<span>}</span>
<span>@Override</span>
<span>public</span> <span>boolean</span> <span>equals</span><span>(</span><span>Object</span> <span>obj</span><span>)</span> <span>{</span>
<span>if</span> <span>(</span><span>this</span> <span>==</span> <span>obj</span><span>)</span> <span>{</span>
<span>return</span> <span>true</span><span>;</span>
<span>}</span> <span>else</span> <span>if</span> <span>(!(</span><span>obj</span> <span>instanceof</span> <span>Person</span><span>))</span> <span>{</span>
<span>return</span> <span>false</span><span>;</span>
<span>}</span> <span>else</span> <span>{</span>
<span>Person</span> <span>other</span> <span>=</span> <span>(</span><span>Person</span><span>)</span> <span>obj</span><span>;</span>
<span>return</span> <span>Objects</span><span>.</span><span>equals</span><span>(</span><span>name</span><span>,</span> <span>other</span><span>.</span><span>name</span><span>)</span>
<span>&&</span> <span>Objects</span><span>.</span><span>equals</span><span>(</span><span>address</span><span>,</span> <span>other</span><span>.</span><span>address</span><span>);</span>
<span>}</span>
<span>}</span>
<span>@Override</span>
<span>public</span> <span>String</span> <span>toString</span><span>()</span> <span>{</span>
<span>return</span> <span>"Person [name="</span> <span>+</span> <span>name</span> <span>+</span> <span>", address="</span> <span>+</span> <span>address</span> <span>+</span> <span>"]"</span><span>;</span>
<span>}</span>
<span>public</span> <span>String</span> <span>getName</span><span>()</span> <span>{</span>
<span>return</span> <span>name</span><span>;</span>
<span>}</span>
<span>public</span> <span>String</span> <span>getAddress</span><span>()</span> <span>{</span>
<span>return</span> <span>address</span><span>;</span>
<span>}</span>
<span>public</span> <span>void</span> <span>setName</span><span>(</span><span>String</span> <span>name</span><span>)</span> <span>{</span>
<span>this</span><span>.</span><span>name</span> <span>=</span> <span>name</span><span>;</span>
<span>}</span>
<span>public</span> <span>void</span> <span>setAddress</span><span>(</span><span>String</span> <span>address</span><span>)</span> <span>{</span>
<span>this</span><span>.</span><span>address</span> <span>=</span> <span>address</span><span>;</span>
<span>}</span>
<span>}</span>
<span>public</span> <span>class</span> <span>Person</span> <span>{</span>

 <span>private</span> <span>final</span> <span>String</span> <span>name</span><span>;</span>
 <span>private</span> <span>final</span> <span>String</span> <span>address</span><span>;</span>

 <span>public</span> <span>Person</span><span>(</span><span>String</span> <span>name</span><span>,</span> <span>String</span> <span>address</span><span>)</span> <span>{</span>
  <span>this</span><span>.</span><span>name</span> <span>=</span> <span>name</span><span>;</span>
  <span>this</span><span>.</span><span>address</span> <span>=</span> <span>address</span><span>;</span>
 <span>}</span>

 <span>@Override</span>
 <span>public</span> <span>int</span> <span>hashCode</span><span>()</span> <span>{</span>
  <span>return</span> <span>Objects</span><span>.</span><span>hash</span><span>(</span><span>name</span><span>,</span> <span>address</span><span>);</span>
 <span>}</span>

 <span>@Override</span>
 <span>public</span> <span>boolean</span> <span>equals</span><span>(</span><span>Object</span> <span>obj</span><span>)</span> <span>{</span>
  <span>if</span> <span>(</span><span>this</span> <span>==</span> <span>obj</span><span>)</span> <span>{</span>
   <span>return</span> <span>true</span><span>;</span>
  <span>}</span> <span>else</span> <span>if</span> <span>(!(</span><span>obj</span> <span>instanceof</span> <span>Person</span><span>))</span> <span>{</span>
   <span>return</span> <span>false</span><span>;</span>
  <span>}</span> <span>else</span> <span>{</span>
   <span>Person</span> <span>other</span> <span>=</span> <span>(</span><span>Person</span><span>)</span> <span>obj</span><span>;</span>
   <span>return</span> <span>Objects</span><span>.</span><span>equals</span><span>(</span><span>name</span><span>,</span> <span>other</span><span>.</span><span>name</span><span>)</span>
     <span>&&</span> <span>Objects</span><span>.</span><span>equals</span><span>(</span><span>address</span><span>,</span> <span>other</span><span>.</span><span>address</span><span>);</span>
  <span>}</span>
 <span>}</span>

 <span>@Override</span>
 <span>public</span> <span>String</span> <span>toString</span><span>()</span> <span>{</span>
  <span>return</span> <span>"Person [name="</span> <span>+</span> <span>name</span> <span>+</span> <span>", address="</span> <span>+</span> <span>address</span> <span>+</span> <span>"]"</span><span>;</span>
 <span>}</span>

 <span>public</span> <span>String</span> <span>getName</span><span>()</span> <span>{</span>
  <span>return</span> <span>name</span><span>;</span>
 <span>}</span>

 <span>public</span> <span>String</span> <span>getAddress</span><span>()</span> <span>{</span>
  <span>return</span> <span>address</span><span>;</span>
 <span>}</span>

 <span>public</span> <span>void</span> <span>setName</span><span>(</span><span>String</span> <span>name</span><span>)</span> <span>{</span>
  <span>this</span><span>.</span><span>name</span> <span>=</span> <span>name</span><span>;</span>
 <span>}</span>

 <span>public</span> <span>void</span> <span>setAddress</span><span>(</span><span>String</span> <span>address</span><span>)</span> <span>{</span>
  <span>this</span><span>.</span><span>address</span> <span>=</span> <span>address</span><span>;</span>
 <span>}</span>
<span>}</span>
public class Person { private final String name; private final String address; public Person(String name, String address) { this.name = name; this.address = address; } @Override public int hashCode() { return Objects.hash(name, address); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } else if (!(obj instanceof Person)) { return false; } else { Person other = (Person) obj; return Objects.equals(name, other.name) && Objects.equals(address, other.address); } } @Override public String toString() { return "Person [name=" + name + ", address=" + address + "]"; } public String getName() { return name; } public String getAddress() { return address; } public void setName(String name) { this.name = name; } public void setAddress(String address) { this.address = address; } }

Enter fullscreen mode Exit fullscreen mode

Yes, the lastest versions of Java have added Records but the Record syntax doesn’t respect the standard Java get/set nomenclature. The real beauty of case classes is their use together with sealed traits in the match expression.

<span>sealed</span> <span>trait</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>Amoeba</span> <span>extends</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>JellyFish</span> <span>extends</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>Human</span> <span>extends</span> <span>LivingBeing</span>
<span>val</span> <span>being</span><span>:</span> <span>LivingBeing</span> <span>=</span> <span>Amoeba</span>
<span>being</span> <span>match</span> <span>{</span>
<span>case</span> <span>Amoeba</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm an Amoeba"</span><span>)</span>
<span>case</span> <span>JellyFish</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm a Jelly Fish"</span><span>)</span>
<span>case</span> <span>Human</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm Human"</span><span>)</span>
<span>// case _ => not needed because the compiler knows that </span>
<span>// all the cases are covered</span>
<span>}</span>
<span>sealed</span> <span>trait</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>Amoeba</span> <span>extends</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>JellyFish</span> <span>extends</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>Human</span> <span>extends</span> <span>LivingBeing</span>

<span>val</span> <span>being</span><span>:</span> <span>LivingBeing</span> <span>=</span> <span>Amoeba</span>
<span>being</span> <span>match</span> <span>{</span>
  <span>case</span> <span>Amoeba</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm an Amoeba"</span><span>)</span> 
  <span>case</span> <span>JellyFish</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm a Jelly Fish"</span><span>)</span>
  <span>case</span> <span>Human</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm Human"</span><span>)</span>
  <span>// case _ => not needed because the compiler knows that </span>
  <span>// all the cases are covered</span>
<span>}</span>
sealed trait LivingBeing case class Amoeba extends LivingBeing case class JellyFish extends LivingBeing case class Human extends LivingBeing val being: LivingBeing = Amoeba being match { case Amoeba => println("Hi, I'm an Amoeba") case JellyFish => println("Hi, I'm a Jelly Fish") case Human => println("Hi, I'm Human") // case _ => not needed because the compiler knows that // all the cases are covered }

Enter fullscreen mode Exit fullscreen mode

;

Scala doesn’t need semicolons, except for multi instructions on a single line (and I avoid them whenever I can). I think that the semicolon is the stupidest character in the programming world but still it’s everywhere. If the creators of Algol could have seen the future I don’t think they would have introduced it. It distracts you from the flow of “idea to code”. You’ve just written a long block of code just to see the compiler complain that there’a an error that doesn’t make sense, and then 10 minutes later you realize it was the missing semicolon from the line before it.
If you like the Python indentation, Scala has that too. In the latest versions of Scala you can substitute the braces with indentation. Personally I prefer braces, but “Infinite Diversity in Infinite Combinations” is the way.

Match Expressions

The match expression in Scala is the corresponding instruction to the switch statement in Java. It serves the same purpose but it’s much more powerful. The Java switch started out as a copy of the C switch, fortunately the latest Java versions have started to copy a few features from Scala. With the match expression you can choose between the usual integers, but also String and any other case class. It also lets you use the fields in the case class as parameters in the case clause (the part after the =>). And match expressions are a perfect tool when working with lists and all the collection classes.

<span>// simple match on integers</span>
<span>val</span> <span>j</span> <span>=</span> <span>Random</span><span>.</span><span>nextInt</span><span>(</span><span>5</span><span>)</span>
<span>j</span> <span>match</span> <span>{</span>
<span>case</span> <span>1</span> <span>=></span> <span>println</span><span>(</span><span>"uno"</span><span>)</span>
<span>case</span> <span>2</span> <span>=></span> <span>println</span><span>(</span><span>"dos"</span><span>)</span>
<span>case</span> <span>3</span> <span>=></span> <span>println</span><span>(</span><span>"tres"</span><span>)</span>
<span>case</span> <span>_</span> <span>=></span> <span>println</span><span>(</span><span>"I can only count to 3 in spanish"</span><span>)</span>
<span>}</span>
<span>// match on String</span>
<span>val</span> <span>breakfast</span> <span>=</span> <span>"milk"</span>
<span>breakfast</span> <span>match</span> <span>{</span>
<span>case</span> <span>"milk"</span> <span>=></span> <span>println</span><span>(</span><span>"Very light breakfast"</span><span>)</span>
<span>case</span> <span>"milk and cookies"</span> <span>=></span> <span>println</span><span>(</span><span>"Light breakfast"</span><span>)</span>
<span>case</span> <span>"bacon and eggs"</span> <span>=></span> <span>println</span><span>(</span><span>"Harty breakfast"</span><span>)</span>
<span>case</span> <span>_</span> <span>=></span> <span>println</span><span>(</span><span>"Did you have breakfast?"</span><span>)</span>
<span>}</span>
<span>// match on a case class</span>
<span>sealed</span> <span>trait</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>Amoeba</span> <span>extends</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>JellyFish</span> <span>extends</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>Human</span> <span>extends</span> <span>LivingBeing</span>
<span>val</span> <span>being</span><span>:</span> <span>LivingBeing</span> <span>=</span> <span>Amoeba</span>
<span>being</span> <span>match</span> <span>{</span>
<span>case</span> <span>Amoeba</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm an Amoeba"</span><span>)</span>
<span>case</span> <span>JellyFish</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm a Jelly Fish"</span><span>)</span>
<span>case</span> <span>Human</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm Human"</span><span>)</span>
<span>// case _ => not needed because the compiler knows that </span>
<span>// all the cases are covered</span>
<span>}</span>
<span>// previous examples forgetting a case</span>
<span>val</span> <span>being</span><span>:</span> <span>LivingBeing</span> <span>=</span> <span>Amoeba</span>
<span>being</span> <span>match</span> <span>{</span>
<span>case</span> <span>Amoeba</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm an Amoeba"</span><span>)</span>
<span>case</span> <span>JellyFish</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm a Jelly Fish"</span><span>)</span>
<span>}</span>
<span>// Produces the following compiler warning:</span>
<span>// match may not be exhaustive.</span>
<span>// It would fail on pattern case: Human</span>
<span>// more detailed example</span>
<span>sealed</span> <span>trait</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>Amoeba</span><span>(</span><span>size</span><span>:</span> <span>Int</span><span>)</span> <span>extends</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>JellyFish</span><span>(</span><span>poisonous</span><span>:</span> <span>Boolean</span><span>)</span> <span>extends</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>Human</span><span>(</span><span>name</span><span>:</span> <span>String</span><span>)</span> <span>extends</span> <span>LivingBeing</span>
<span>val</span> <span>being</span><span>:</span> <span>LivingBeing</span> <span>=</span> <span>JellyFish</span><span>(</span><span>true</span><span>)</span>
<span>being</span> <span>match</span> <span>{</span>
<span>case</span> <span>Amoeba</span><span>(</span><span>n</span><span>)</span> <span>=></span> <span>println</span><span>(</span><span>s</span><span>"Hi, I'm an Amoeba and I am $n millimeters long"</span><span>)</span>
<span>case</span> <span>JellyFish</span><span>(</span><span>p</span><span>)</span> <span>=></span> <span>println</span><span>(</span><span>s</span><span>"Hi, I'm a Jelly Fish "</span> <span>+</span>
<span>s</span><span>"and I am ${if(p) "" else "</span><span>not</span><span>"} poisonous"</span><span>)</span>
<span>case</span> <span>Human</span><span>(</span><span>n</span><span>)</span> <span>=></span> <span>println</span><span>(</span><span>s</span><span>"Hi, I'm Human and my name is $n"</span><span>)</span>
<span>}</span>
<span>// match on lists</span>
<span>val</span> <span>l</span> <span>=</span> <span>List</span><span>(</span><span>1</span><span>,</span> <span>2</span><span>,</span> <span>3</span><span>,</span> <span>4</span><span>,</span> <span>5</span><span>)</span>
<span>l</span> <span>match</span> <span>{</span>
<span>case</span> <span>List</span><span>(</span><span>_</span><span>,</span> <span>_</span><span>,</span> <span>3</span><span>,</span> <span>_</span><span>,</span> <span>_</span><span>)</span> <span>=></span>
<span>println</span><span>(</span><span>"List of 5 elements with 3 as the third element"</span><span>)</span>
<span>case</span> <span>head</span><span>::</span><span>tail</span> <span>=></span>
<span>println</span><span>(</span><span>s</span><span>"List with $head as the first element, "</span> <span>+</span>
<span>s</span><span>"and $tail as the rest of the list"</span><span>)</span>
<span>case</span> <span>_</span> <span>=></span> <span>println</span><span>(</span><span>"Anything"</span><span>)</span>
<span>}</span>
<span>// simple match on integers</span>
<span>val</span> <span>j</span> <span>=</span> <span>Random</span><span>.</span><span>nextInt</span><span>(</span><span>5</span><span>)</span>
<span>j</span> <span>match</span> <span>{</span>
  <span>case</span> <span>1</span> <span>=></span> <span>println</span><span>(</span><span>"uno"</span><span>)</span>
  <span>case</span> <span>2</span> <span>=></span> <span>println</span><span>(</span><span>"dos"</span><span>)</span>
  <span>case</span> <span>3</span> <span>=></span> <span>println</span><span>(</span><span>"tres"</span><span>)</span>
  <span>case</span> <span>_</span> <span>=></span> <span>println</span><span>(</span><span>"I can only count to 3 in spanish"</span><span>)</span>
<span>}</span>
<span>// match on String</span>
<span>val</span> <span>breakfast</span> <span>=</span> <span>"milk"</span>
<span>breakfast</span> <span>match</span> <span>{</span>
  <span>case</span> <span>"milk"</span> <span>=></span> <span>println</span><span>(</span><span>"Very light breakfast"</span><span>)</span>
  <span>case</span> <span>"milk and cookies"</span> <span>=></span> <span>println</span><span>(</span><span>"Light breakfast"</span><span>)</span>
  <span>case</span> <span>"bacon and eggs"</span> <span>=></span> <span>println</span><span>(</span><span>"Harty breakfast"</span><span>)</span>
  <span>case</span> <span>_</span> <span>=></span> <span>println</span><span>(</span><span>"Did you have breakfast?"</span><span>)</span>
<span>}</span>
<span>// match on a case class</span>
<span>sealed</span> <span>trait</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>Amoeba</span> <span>extends</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>JellyFish</span> <span>extends</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>Human</span> <span>extends</span> <span>LivingBeing</span>

<span>val</span> <span>being</span><span>:</span> <span>LivingBeing</span> <span>=</span> <span>Amoeba</span>
<span>being</span> <span>match</span> <span>{</span>
  <span>case</span> <span>Amoeba</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm an Amoeba"</span><span>)</span> 
  <span>case</span> <span>JellyFish</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm a Jelly Fish"</span><span>)</span>
  <span>case</span> <span>Human</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm Human"</span><span>)</span>
  <span>// case _ => not needed because the compiler knows that </span>
  <span>// all the cases are covered</span>
<span>}</span>
<span>// previous examples forgetting a case</span>
<span>val</span> <span>being</span><span>:</span> <span>LivingBeing</span> <span>=</span> <span>Amoeba</span>
<span>being</span> <span>match</span> <span>{</span>
  <span>case</span> <span>Amoeba</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm an Amoeba"</span><span>)</span> 
  <span>case</span> <span>JellyFish</span> <span>=></span> <span>println</span><span>(</span><span>"Hi, I'm a Jelly Fish"</span><span>)</span>
<span>}</span>
<span>// Produces the following compiler warning:</span>
<span>// match may not be exhaustive.</span>
<span>// It would fail on pattern case: Human</span>

<span>// more detailed example</span>
<span>sealed</span> <span>trait</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>Amoeba</span><span>(</span><span>size</span><span>:</span> <span>Int</span><span>)</span> <span>extends</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>JellyFish</span><span>(</span><span>poisonous</span><span>:</span> <span>Boolean</span><span>)</span> <span>extends</span> <span>LivingBeing</span>
<span>case</span> <span>class</span> <span>Human</span><span>(</span><span>name</span><span>:</span> <span>String</span><span>)</span> <span>extends</span> <span>LivingBeing</span>

<span>val</span> <span>being</span><span>:</span> <span>LivingBeing</span> <span>=</span> <span>JellyFish</span><span>(</span><span>true</span><span>)</span>
<span>being</span> <span>match</span> <span>{</span>
  <span>case</span> <span>Amoeba</span><span>(</span><span>n</span><span>)</span> <span>=></span> <span>println</span><span>(</span><span>s</span><span>"Hi, I'm an Amoeba and I am $n millimeters long"</span><span>)</span>
  <span>case</span> <span>JellyFish</span><span>(</span><span>p</span><span>)</span> <span>=></span> <span>println</span><span>(</span><span>s</span><span>"Hi, I'm a Jelly Fish "</span> <span>+</span>
    <span>s</span><span>"and I am ${if(p) "" else "</span><span>not</span><span>"} poisonous"</span><span>)</span>
  <span>case</span> <span>Human</span><span>(</span><span>n</span><span>)</span> <span>=></span> <span>println</span><span>(</span><span>s</span><span>"Hi, I'm Human and my name is $n"</span><span>)</span>
<span>}</span>

<span>// match on lists</span>
<span>val</span> <span>l</span> <span>=</span> <span>List</span><span>(</span><span>1</span><span>,</span> <span>2</span><span>,</span> <span>3</span><span>,</span> <span>4</span><span>,</span> <span>5</span><span>)</span>
<span>l</span> <span>match</span> <span>{</span>
  <span>case</span> <span>List</span><span>(</span><span>_</span><span>,</span> <span>_</span><span>,</span> <span>3</span><span>,</span> <span>_</span><span>,</span> <span>_</span><span>)</span> <span>=></span>
    <span>println</span><span>(</span><span>"List of 5 elements with 3 as the third element"</span><span>)</span>
  <span>case</span> <span>head</span><span>::</span><span>tail</span> <span>=></span>
    <span>println</span><span>(</span><span>s</span><span>"List with $head as the first element, "</span> <span>+</span>
      <span>s</span><span>"and $tail as the rest of the list"</span><span>)</span>
  <span>case</span> <span>_</span> <span>=></span> <span>println</span><span>(</span><span>"Anything"</span><span>)</span>
<span>}</span>
// simple match on integers val j = Random.nextInt(5) j match { case 1 => println("uno") case 2 => println("dos") case 3 => println("tres") case _ => println("I can only count to 3 in spanish") } // match on String val breakfast = "milk" breakfast match { case "milk" => println("Very light breakfast") case "milk and cookies" => println("Light breakfast") case "bacon and eggs" => println("Harty breakfast") case _ => println("Did you have breakfast?") } // match on a case class sealed trait LivingBeing case class Amoeba extends LivingBeing case class JellyFish extends LivingBeing case class Human extends LivingBeing val being: LivingBeing = Amoeba being match { case Amoeba => println("Hi, I'm an Amoeba") case JellyFish => println("Hi, I'm a Jelly Fish") case Human => println("Hi, I'm Human") // case _ => not needed because the compiler knows that // all the cases are covered } // previous examples forgetting a case val being: LivingBeing = Amoeba being match { case Amoeba => println("Hi, I'm an Amoeba") case JellyFish => println("Hi, I'm a Jelly Fish") } // Produces the following compiler warning: // match may not be exhaustive. // It would fail on pattern case: Human // more detailed example sealed trait LivingBeing case class Amoeba(size: Int) extends LivingBeing case class JellyFish(poisonous: Boolean) extends LivingBeing case class Human(name: String) extends LivingBeing val being: LivingBeing = JellyFish(true) being match { case Amoeba(n) => println(s"Hi, I'm an Amoeba and I am $n millimeters long") case JellyFish(p) => println(s"Hi, I'm a Jelly Fish " + s"and I am ${if(p) "" else "not"} poisonous") case Human(n) => println(s"Hi, I'm Human and my name is $n") } // match on lists val l = List(1, 2, 3, 4, 5) l match { case List(_, _, 3, _, _) => println("List of 5 elements with 3 as the third element") case head::tail => println(s"List with $head as the first element, " + s"and $tail as the rest of the list") case _ => println("Anything") }

Enter fullscreen mode Exit fullscreen mode

String Interpolation

In Scala there is a much simpler way to substitute variable values inside strings. There are 3 string interpolators, the “s”, “f” and “raw” interpolators. The s interpolator just substitutes any variables preceded by a $ or any expression inside ${} with its value. The f interpolator does the same as the s but you can add formatting using the printf style formats. The raw interpolator does the same as the s but it doesn’t perform escaping of literals. Here are a few examples.

<span>// using the s interpolator</span>
<span>// substitute simple variables using $</span>
<span>val</span> <span>head</span> <span>=</span> <span>15</span>
<span>val</span> <span>tail</span> <span>=</span> <span>List</span><span>(</span><span>25</span><span>,</span> <span>12</span><span>,</span> <span>32</span><span>)</span>
<span>println</span><span>(</span><span>s</span><span>"List with $head as the first element, and $tail as the rest of the list"</span><span>)</span>
<span>// substitute any expression using ${}</span>
<span>val</span> <span>p</span> <span>=</span> <span>true</span>
<span>println</span><span>(</span><span>s</span><span>"Hi, I'm a Jelly Fish and I am ${if(p) "" else "</span><span>not</span><span>"} poisonous"</span><span>)</span>
<span>// substitute values and formats using the f interpolator</span>
<span>val</span> <span>fl</span> <span>=</span> <span>12.45</span>
<span>val</span> <span>st</span> <span>=</span> <span>13</span>
<span>println</span><span>(</span><span>f</span><span>"the fixed width left justified value is $st%-5s;"</span><span>)</span>
<span>// prints -> the fixed width left justified value is 13 ;</span>
<span>println</span><span>(</span><span>f</span><span>"the floating point value is $fl%2.2f"</span><span>)</span>
<span>// prints -> the floating point value is 12,45</span>
<span>// using the s interpolator</span>
<span>// substitute simple variables using $</span>
<span>val</span> <span>head</span> <span>=</span> <span>15</span>
<span>val</span> <span>tail</span> <span>=</span> <span>List</span><span>(</span><span>25</span><span>,</span> <span>12</span><span>,</span> <span>32</span><span>)</span>
<span>println</span><span>(</span><span>s</span><span>"List with $head as the first element, and $tail as the rest of the list"</span><span>)</span>
<span>// substitute any expression using ${}</span>
<span>val</span> <span>p</span> <span>=</span> <span>true</span>
<span>println</span><span>(</span><span>s</span><span>"Hi, I'm a Jelly Fish and I am ${if(p) "" else "</span><span>not</span><span>"} poisonous"</span><span>)</span>
<span>// substitute values and formats using the f interpolator</span>
<span>val</span> <span>fl</span> <span>=</span> <span>12.45</span>
<span>val</span> <span>st</span> <span>=</span> <span>13</span>
<span>println</span><span>(</span><span>f</span><span>"the fixed width left justified value is $st%-5s;"</span><span>)</span>
<span>// prints -> the fixed width left justified value is 13 ;</span>
<span>println</span><span>(</span><span>f</span><span>"the floating point value is $fl%2.2f"</span><span>)</span>
<span>// prints -> the floating point value is 12,45</span>
// using the s interpolator // substitute simple variables using $ val head = 15 val tail = List(25, 12, 32) println(s"List with $head as the first element, and $tail as the rest of the list") // substitute any expression using ${} val p = true println(s"Hi, I'm a Jelly Fish and I am ${if(p) "" else "not"} poisonous") // substitute values and formats using the f interpolator val fl = 12.45 val st = 13 println(f"the fixed width left justified value is $st%-5s;") // prints -> the fixed width left justified value is 13 ; println(f"the floating point value is $fl%2.2f") // prints -> the floating point value is 12,45

Enter fullscreen mode Exit fullscreen mode

val & var

In Scala it is discouraged to use mutable variables. It is a tenet of FP but also by using immutable variables the code is easier to reason about and less error prone. In async code immutable variables avoid deadlocks and race conditions. The val keyword indicates an immutable variable while var indicates a mutable one. If you instantiate a val and then try to reassign it, the compiler will complain. This tells you that you either should have used a mutable variable or there is something wrong in your code.

Everything is an Object

Java is an object oriented language so why does it have primitive non object types? Scala has solved the problem by making the Java primitives full fledged objects. Also, the object hierarchy is slightly modified to allow consistency and compatability with FP principles.

Everything is an Expression

In Scala, everything is an expression. This means that everything returns a value. You can assign the result of a for, if or match expression to a variable. This way you can avoid the use of mutable variables and repeated assignments inside the corresponding statements.

<span>// for statement</span>
<span>// even though it is declared with val the ListBuffer is a mutable collection</span>
<span>val</span> <span>lb</span><span>:</span> <span>ListBuffer</span><span>[</span><span>Int</span><span>]</span> <span>=</span> <span>new</span> <span>ListBuffer</span>
<span>for</span><span>(</span><span>i</span> <span><-</span> <span>0</span> <span>to</span> <span>10</span><span>)</span> <span>{</span>
<span>lb</span><span>.</span><span>append</span><span>(</span><span>i</span><span>)</span>
<span>}</span>
<span>// for expression</span>
<span>val</span> <span>y</span> <span>=</span> <span>for</span><span>(</span><span>i</span> <span><-</span> <span>0</span> <span>to</span> <span>10</span><span>)</span> <span>yield</span> <span>i</span>
<span>// match statement with mutable variable and multiple assignments</span>
<span>var</span> <span>x</span> <span>=</span> <span>"some initial value"</span>
<span>val</span> <span>r</span> <span>=</span> <span>10</span>
<span>r</span> <span>match</span> <span>{</span>
<span>case</span> <span>5</span> <span>=></span> <span>x</span> <span>=</span> <span>"5"</span>
<span>case</span> <span>10</span> <span>=></span> <span>x</span> <span>=</span> <span>"10"</span>
<span>case</span> <span>_</span> <span>=></span> <span>x</span> <span>=</span> <span>"0"</span>
<span>}</span>
<span>// match expression</span>
<span>val</span> <span>r</span> <span>=</span> <span>10</span>
<span>val</span> <span>x</span> <span>=</span> <span>r</span> <span>match</span> <span>{</span>
<span>case</span> <span>5</span> <span>=></span> <span>"5"</span>
<span>case</span> <span>10</span> <span>=></span> <span>"10"</span>
<span>case</span> <span>_</span> <span>=></span> <span>"0"</span>
<span>}</span>
<span>// if statement with mutable variable and multiple assignments</span>
<span>var</span> <span>ok</span> <span>=</span> <span>"some initial value"</span>
<span>val</span> <span>n</span> <span>=</span> <span>15</span>
<span>if</span><span>(</span><span>n</span> <span><</span> <span>30</span><span>)</span> <span>ok</span> <span>=</span> <span>x</span>
<span>else</span> <span>ok</span> <span>=</span> <span>"30+"</span>
<span>// if expression</span>
<span>val</span> <span>n</span> <span>=</span> <span>15</span>
<span>val</span> <span>ok</span> <span>=</span> <span>if</span><span>(</span><span>n</span> <span><</span> <span>30</span><span>)</span> <span>x</span> <span>else</span> <span>"30+"</span>
<span>// for statement</span>
<span>// even though it is declared with val the ListBuffer is a mutable collection</span>
<span>val</span> <span>lb</span><span>:</span> <span>ListBuffer</span><span>[</span><span>Int</span><span>]</span> <span>=</span> <span>new</span> <span>ListBuffer</span>
<span>for</span><span>(</span><span>i</span> <span><-</span> <span>0</span> <span>to</span> <span>10</span><span>)</span> <span>{</span>
  <span>lb</span><span>.</span><span>append</span><span>(</span><span>i</span><span>)</span>
<span>}</span>
<span>// for expression</span>
<span>val</span> <span>y</span> <span>=</span> <span>for</span><span>(</span><span>i</span> <span><-</span> <span>0</span> <span>to</span> <span>10</span><span>)</span> <span>yield</span> <span>i</span>

<span>// match statement with mutable variable and multiple assignments</span>
<span>var</span> <span>x</span> <span>=</span> <span>"some initial value"</span>
<span>val</span> <span>r</span> <span>=</span> <span>10</span>
<span>r</span> <span>match</span> <span>{</span>
  <span>case</span> <span>5</span> <span>=></span> <span>x</span> <span>=</span> <span>"5"</span>
  <span>case</span> <span>10</span> <span>=></span> <span>x</span> <span>=</span> <span>"10"</span>
  <span>case</span> <span>_</span> <span>=></span> <span>x</span> <span>=</span> <span>"0"</span>
<span>}</span>
<span>// match expression</span>
<span>val</span> <span>r</span> <span>=</span> <span>10</span>
<span>val</span> <span>x</span> <span>=</span> <span>r</span> <span>match</span> <span>{</span>
  <span>case</span> <span>5</span> <span>=></span> <span>"5"</span>
  <span>case</span> <span>10</span> <span>=></span> <span>"10"</span>
  <span>case</span> <span>_</span> <span>=></span> <span>"0"</span>
<span>}</span>

<span>// if statement with mutable variable and multiple assignments</span>
<span>var</span> <span>ok</span> <span>=</span> <span>"some initial value"</span>
<span>val</span> <span>n</span> <span>=</span> <span>15</span>
<span>if</span><span>(</span><span>n</span> <span><</span> <span>30</span><span>)</span> <span>ok</span> <span>=</span> <span>x</span> 
<span>else</span> <span>ok</span> <span>=</span> <span>"30+"</span>
<span>// if expression</span>
<span>val</span> <span>n</span> <span>=</span> <span>15</span>
<span>val</span> <span>ok</span> <span>=</span> <span>if</span><span>(</span><span>n</span> <span><</span> <span>30</span><span>)</span> <span>x</span> <span>else</span> <span>"30+"</span>
// for statement // even though it is declared with val the ListBuffer is a mutable collection val lb: ListBuffer[Int] = new ListBuffer for(i <- 0 to 10) { lb.append(i) } // for expression val y = for(i <- 0 to 10) yield i // match statement with mutable variable and multiple assignments var x = "some initial value" val r = 10 r match { case 5 => x = "5" case 10 => x = "10" case _ => x = "0" } // match expression val r = 10 val x = r match { case 5 => "5" case 10 => "10" case _ => "0" } // if statement with mutable variable and multiple assignments var ok = "some initial value" val n = 15 if(n < 30) ok = x else ok = "30+" // if expression val n = 15 val ok = if(n < 30) x else "30+"

Enter fullscreen mode Exit fullscreen mode

Type Inference

Scala, just like Java, is a strongly typed language and yet in Scala you can write code like you were writing in Python. Most of the time you don’t need to specify the type of a variable in Scala because the compiler infers the type from the context. The only places you need to specify the types are function parameters and the return types of recursive functions. It can be very useful, with an IDE that shows the inferred type, to check on a calculation by checking if the inferred type is what you expected.

Collection Classes

The image below, taken from
https://docs.scala-lang.org/scala3/book/collections-classes.html,
shows the great variety of collections to choose from in Scala. There is also an analogous tree of collection classes for the mutable classes that are implemented in the same way but allow you to add, remove or reorder elements.

null

You can write in Scala using null, but I think you should make an effort to avoid it. There are classes like Option or Either that solve the problem of null and make your life as a programmer much easier. The Option class encodes the idea of the existence of a value or not. You can return a value from a function as a Some(x) (where x is the value you need to return from the function) or None if the value the function should return does not exist. By annotating that the function returns an Option of some type the function signature automatically expresses the fact that the function may not return a value. It is basically what null does in Java but you don’t need to have error handling in your code and you can’t forget to manage the absence of a value because the compiler will tell you, say goodbye to NPEs.

Try it, you won’t regret it

In summary you can just start using Scala in place of Java and then little by little start coding in the functional style and see if you feel at ease with it or not.

原文链接:Programming in Scala as a “Better” Java

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
The worst sort of indolence is being given a choice, yet taking no initiative to change.
我们人生中最大的懒惰,就是当我们明知自己拥有作出选择的能力,却不去主动改变而是放任它的生活态度
评论 抢沙发

请登录后发表评论

    暂无评论内容