Scala - Getting Started - Part 1
- 18 minutes read - 3687 wordsThis article help you to start with Scala, with step by step guide and series of examples. It starts with an overview and then covers in detail examples. In later articles, I will write about feature comparison with other languages. It article is helpful for people coming from Java background, how it is not the prerequisites.
Scala Overview
Scala is a general purpose programming language designed to express common programming patterns in a concise, elegant, and type-safe way. It smoothly integrates features of object-oriented and functional languages, enabling Java and other programmers to be more productive.
Features
While the simplicity and ease of use is the leading principle of Scala here are a few nice features of Scala:
-
Code sizes are typically reduced by a factor of two to three when compared to an equivalent Java application.
-
As compared to java, Scala boost their development productivity, applications scalability and overall reliability.
-
Seamless integration with Java : Existing Java code and programmer skills are fully re-usable. Scala programs run on the Java VM are byte code compatible with Java so you can make full use of existing Java libraries or existing application code. You can call Scala from Java and you can call Java from Scala, the integration is seamless.
-
Scala Compiler Performance: The Scala compiler is mature and proven highly reliable by years of use in production environments, the compiler was written by Martin Odersky who also wrote the Java reference compiler and co-authored the generics. Scala compiler produces byte code that performs every bit as good as comparable Java code.
-
Scala is object-oriented: Scala is a pure object-oriented language in the sense that every value is an object. Types and behavior of objects are described by classes and traits. Classes are extended by sub classing and a flexible mixing-based composition mechanism as a clean replacement for multiple inheritance.
Traits are Scala’s replacement for Java’s interfaces. Interfaces in Java are highly restricted, able only to contain abstract function declarations. This has led to criticism that providing convenience methods in interfaces is awkward (the same methods must be re implemented in every implementation), and extending a published interface in a backwards-compatible way is impossible. Traits are similar to mixing classes in that they have nearly all the power of a regular abstract class, lacking only class parameters (Scala’s equivalent to Java’s constructor parameters), since traits are always mixed in with a class.
-
Scala is functional: Scala is also a functional language in the sense that every function is a value.
- Scala provides a lightweight syntax for defining anonymous functions.
- It supports higher-order functions : These are functions that take other functions as parameters, or whose result is a function.
- It allows functions to be nested:.
- It supports currying: Methods may define multiple parameter lists. When a method is called with a fewer number of parameter lists, then this will yield a function taking the missing parameter lists as its arguments.
- Scala interoperates with Java and .NET: Scala is designed to interoperate well with the popular Java 2 Runtime Environment (JRE). In particular, the interaction with the mainstream object-oriented Java programming language is as smooth as possible. Scala has the same compilation model (separate compilation, dynamic class loading) like Java and allows access to thousands of existing high-quality libraries. Support for the .NET Framework (CLR) is also available.
Working with Scala
Lets start with few Scala examples. Here is what you need
- Eclipse 3.7 or Eclipse 4.2
- Java 1.6 or above.
- Scala Binary - 2.10.1/(2.9.2 – for ant integration example only)
Hello World (Main method)
Lets understand basic scala program things to keen in mind
- A Scala source files ends with the extension
.scala
. - Scala methods are public by default, which means there’s no public method modifier (private and protected are both defined)
- Scala doesn’t really have statics. It has a special syntax which allows you to easily define and use singleton classes.
object
keyword creating a Singleton object of a class. For every object in the code, an anonymous class is created, which inherits from whatever classes you declared
Rest is all java :)
package com.tk.scala
/**
* There is nothing called 'static' in scala, This way we are creating singleton object
*/
object MainClass {
/**
* args is a method parameter of type Array[String].
* That is to say, args is a string array.
*
* ':Unit' defines the return type of the main function
* Unit is like void but its more than that.
*/
def main(args:Array[String]):Unit = {
//declaration of String variable firstName
var firstName: String = "Kuldeep";
// similar declaration as above String. However, we don’t explicitly
// specify any type.
// This is because we’re taking advantage of Scala’s type inference mechanism
var lastName = "Singh";
// val represents the declaration of constant
// Think of it like a shorter form of Java’s final modifier
val greeting:String = "Hello"
println(greeting + " " + firstName + " " + lastName)
}
}
Hello World ( with Application class)
Below program show the use of Application
class (trait) in Scala. Inspite of declaring main function in above example we can take advantage of ‘Application’ class.
- The Application trait can be used to quickly turn objects into executable programs.
- Drawback of using Application class to make program executable is that there is no way to obtain the command-line arguments because all code in body of an object extending Application is run as part of the static initialization which occurs before Application’s main method even begins execution.
package com.tk.scala
object MainClass extends Application {
//declaration of String variable firstName
var firstName: String = "Kuldeep";
var lastName = "Singh";
val greeting:String = "Hello"
println(greeting + " " + firstName + " " + lastName)
}
Byte code generation
.Scala
file is converted into .class
file as JVM only understands byte code. This is how ‘.class’ look file when decompiled with the java decompiler.
We can see here the singleton class MainClass as mentioned above ‘Object’ keyword in Scala in equivalent to singleton class in java.
package com.tk.scala;
import scala.Predef.;
import scala.collection.mutable.StringBuilder;
// Singleton class
public final class MainClass$
{
public static final MODULE$;
static
{
new ();
}
public void main(String[] args)
{
String firstName = "Kuldeep";
String lastName = "Singh";
String greeting = "Hello";
Predef..MODULE$.println(new StringBuilder().append(greeting).append(" ").append(firstName).append(" ").append(lastName).toString());
}
// private constructor of singleton class
private MainClass$()
{
MODULE$ = this;
}
}
Encapsulation in Scala
This example demonstrate simple encapsulation concept using Scala program
- Declaration of private member in scala and defining its setter getter
package com.tk.scala
class Product {
// declaration of private Int variable price
private var _price: Int = 0
// definition of getter method for price
// method name price returning Int variable price
def price = _price
// above declaration is same as
// def price:Int = {_price};
// definition of setter method
// here underscore is acting like a reserve keyword
def price_=(value: Int): Unit = _price = value
}
/**
* Main object
*/
object AppMainClass {
def main(args: Array[String]) =
{
var product = new Product();
// calling setter to set value
product.price = 12;
print("Price of product is: ")
println(product.price)
}
}
Byte code
This is how .class looks when decompiled with java decompiler.
public class Product
{
private int _price = 0;
private int _price() { return this._price; }
private void _price_$eq(int x$1) { this._price = x$1; }
public int price()
{
return _price();
}
public void price_$eq(int value)
{
_price_$eq(value);
}
}
public final class AppMainFx$
{
public static final MODULE$;
static
{
new ();
}
public void main(String[] args)
{
Product product = new Product();
product.price_$eq(12);
Predef..MODULE$.print("Price of product is: ");
Predef..MODULE$.println(BoxesRunTime.boxToInteger(product.price()));
}
private AppMainFx$()
{
MODULE$ = this;
}
}
General OOPs in Scala
This example demonstrate simple OOPS concept using Scala program
- Scala doesn’t force you to define all public classes individually in files of the same name. Scala actually lets you define as many classes as you want per file (think C++ or Ruby).
- Demonstration of inheritance using scala.
- Constructor’s declarations.
- Overriding the methods.
package com.tk.scala
/**
* Abstract Class declaration
*/
abstract class Person {
// constant declaration of type string using keyword ‘val’
val SPACE: String = " "
/**
* These are a public variable (Scala elements are public by default)
*
* Scala supports encapsulation as well, but its syntax is considerably
* less verbose than Java’s. Effectively, all public variables become instance
* properties.
*/
var firstName: String = null
var lastName: String = null
// abstract method
def getDetails(): Unit
}
/**
* Concrete Employee class extending person class
*
* Constructor: Employee class with parameterized constructor with two
* parameters firstName and lastName inherited from Person class.
* The constructor isn’t a special method syntactically like in java,
* it is the body of the class itself.
*/
class Employee(firstName: String, lastName: String) extends Person {
val profession:String = "Employee";
// implementation of abstract methods
def getDetails() = {
println("Personal Details: " + firstName + SPACE + lastName)
}
/**
* Override is actually a keyword.
* It is a mandatory method modifier for any method with a signature which
* conflicts with another method in a superclass.
* Thus overriding in Scala isn’t implicit (as in Java, Ruby, C++, etc), but explicitly declared.
*/
override def toString = "[" + profession +": firstName=" + firstName + " lastName=" + lastName + "]"
}
/**
* Concrete Teacher class extending person class
*/
class Teacher(firstName: String, lastName: String) extends Person {
val profession:String = "Teacher";
def getDetails() = {
println("Personal Details: " + firstName + SPACE + lastName)
}
override def toString = "[" + profession +": firstName=" + firstName + " lastName=" + lastName + "]"
}
object App {
def main(args: Array[String]) =
{
var emp = new Employee("Kuldeep", "Singh");
println(emp);
var teacher = new Teacher("Kuldeep", "Thinker")
println(teacher)
}
}
Collections in Scala
This example demonstrates some Collections in scala.
- Scala
List
s are quite similar to arrays which means, all the elements of a list have the same type but there are two important differences.- Lists are immutable which means, elements of a list cannot be changed by assignment.
- Lists represent a linked list whereas arrays are flat.
- Scala Sets: There are two kinds of Sets, the immutable and the mutable. The difference between mutable and immutable objects is that when an object is immutable, the object itself can’t be changed.
- By default, Scala uses the immutable
Set
. If you want to use the mutableSet
, you’ll have to importscala.collection.mutable.Set
class explicitly.
- By default, Scala uses the immutable
- Scala
Map
s: Similar to sets there are two kinds of maps immutable and mutable. - Scala
Tuple
s: Scala tuple combines a fixed number of items together so that they can be passed around as a whole. Unlike an array or list, a tuple can hold objects with different types but they are also immutable.
package com.tk.scala
/**
* Class demonstrating list
*/
class ScalaList {
/**
* Creation list of types string
*/
val fruit1: List[String] = List("apples", "oranges", "pears")
/**
* All lists can be defined using two fundamental building blocks,
* a tail Nil and :: which is pronounced cons. Nil also represents the empty list.
*/
val fruit2 = "apples" :: ("oranges" :: ("pears" :: Nil))
val empty = Nil
/**
* Operations supported on list
* As scala list is LinkList, operations as related to general link list operations/
*
* Some operations
*/
def Operations(): Unit = {
println("Head of fruit : " + fruit1.head)
println("Tail of fruit : " + fruit1.tail)
println("Check if fruit is empty : " + fruit1.isEmpty)
println("Check if nums is empty : " + fruit1.isEmpty)
println("Check if nums is empty : " + empty.isEmpty)
traverseList
}
def traverseList() = {
val iterator = fruit1.iterator;
while (iterator.hasNext) {
print(iterator.next())
print("->")
}
println
}
}
/**
* Class demonstrating sets
*/
class ScalaSet {
// Empty set of integer type
var emptySet: Set[Int] = Set()
// Set of integer type
var oddIntegerSet: Set[Int] = Set(1, 3, 5, 7)
var evenIntegerSet: Set[Int] = Set(2, 4, 6, 8)
def operations(): Unit = {
println("Head of fruit : " + oddIntegerSet.head)
println("Tail of fruit : " + oddIntegerSet.tail)
println("Check if fruit is empty : " + oddIntegerSet.isEmpty)
println("Check if nums is empty : " + oddIntegerSet.isEmpty)
println("Check if nums is empty : " + emptySet.isEmpty)
//Concatenating Sets
var concatinatedList = oddIntegerSet ++ evenIntegerSet
println("Concatinated List : " + concatinatedList)
}
}
/**
* Class demonstrating maps
*/
class ScalaMap {
// Empty hash table whose keys are strings and values are integers:
/**
* Note: While defining empty map, the type annotation is necessary
* as the system needs to assign a concrete type to variable.
*/
var emptyMap: Map[Char, Int] = Map()
val colors = Map("red" -> "#FF0000",
"azure" -> "#F0FFFF",
"peru" -> "#CD853F")
def operations() = {
println("Keys in colors : " + colors.keys)
println("Values in colors : " + colors.values)
println("Check if colors is empty : " + colors.isEmpty)
println("Check if nums is empty : " + emptyMap.isEmpty)
tranverseMap
}
def tranverseMap() {
println("Printing key value pair for map:::")
// using for each loop to traverse map
colors.keys.foreach { i =>
print("Key = " + i)
println(" Value = " + colors(i))
}
}
}
/**
* Class demonstrating tuples
*/
class scalaTuple {
val t = new Tuple3(1, "hello", Console)
//same tuple can be declared as
val t1 = (1, "hello", Console)
val intergerTuple = (4, 3, 2, 1)
def operations() = {
println("Print sum of elements in integer tuples")
val sum = intergerTuple._1 + intergerTuple._2 + intergerTuple._3 + intergerTuple._4
transverseTuple
}
def transverseTuple {
println("Printing elements in tuples:::")
intergerTuple.productIterator.foreach { i => println("Value = " + i) }
}
}
object CollectionMain {
def main(args: Array[String]) =
{
var scalaList = new ScalaList();
println("Printing operations on list::::")
scalaList.Operations;
var scalaSet = new ScalaSet();
println("");
println("Printing operations on Set::::")
scalaSet.operations;
var scalaMap = new ScalaMap();
println("");
println("Printing operations on Map::::")
scalaMap.operations;
var scalaTuple = new scalaTuple();
println("");
println("Printing operations on Tuple::::")
scalaTuple.operations;
}
}
File operations & Exception handling
- Exceptions in Scala: Scala doesn’t actually have checked exceptions. Scala allows you to try/catch any exception in a single block and then perform pattern matching against it using case blocks as shown below
package com.tk.scala
import java.io.IOException
import java.io.FileNotFoundException
import scala.io.Source
import scala.reflect.io.Path
import java.io.File
import java.io.PrintWriter
/**
* Scala example to show read and write operations on file
*/
class FileOperations {
/**
* create and add content to file
*
* This example depicts how we use java API in scala
* We can use any java class/API in scala
*/
def writeFile(filePath:String, content:String) = {
// using java file object to create a file
var file:File = new File(filePath);
if (file.createNewFile()) {
println("New file created")
} else {
println("File alredy exists")
}
// using java print writer object to add content in file
var writer:PrintWriter = new PrintWriter(file);
if (content != null)
writer.write(content)
writer.close();
}
/**
* reads the given file are return the content
* of that file
*/
def readFile(filePath: String): String = {
// here is scala io class to readfrom file
var lines: String = null;
// there is no checked exception in scala
try {
lines = scala.io.Source.fromFile(filePath).mkString
// catch block for exception handing
} catch {
case ex: FileNotFoundException => {
println("Missing file exception")
}
case ex: IOException => {
println("IO Exception")
}
} finally {
println("Exiting finally...")
}
// returning content of the file
lines
}
}
/**
* Main object
*/
object FileOperationMain extends Application {
val filePath = "e:\\test.txt"
var fileOpts: FileOperations = new FileOperations;
// calling api to create/write file
fileOpts.writeFile(filePath, "File operation example for scala");
// calling api to read file
println(fileOpts.readFile(filePath));
}
Triat
- A trait encapsulates method and field definitions, which can then be reused by mixing them into classes. Unlike class inheritance, in which each class must inherit from just one superclass, a class can mix in any number of traits.
- A trait definition looks just like a class definition except that it uses the keyword trait as follows
- Explains how scala support mixed bases composition.
package com.tk.scala
/**
* defining a trait
* Trait can have abstract method as well
* as well as concrete method
*/
trait Swimming {
def swim() = println("I can swim")
}
/**
* fly trait
*/
trait Fly {
def fly() = println("I can fly")
}
/**
* abstract class bird
*/
abstract class Bird {
//abstract method
def defineMe: String
}
/**
* class having bird as well as trait properties
*/
class Penguin extends Bird with Swimming {
/**
* Short hand syntax of function defination
* Following line means function flyMessage is
* returing string value <I am good..>
*/
def defineMe = "I am a Penguin"
/**
* This piece of code is equivalent to above definition of function
*/
/*def defineMe() = {
var str:String = "I am a Penguin"
// returning string value (No return keyword required)
str
}*/
}
/**
* class having all the traits
*/
class Pigeon extends Bird with Swimming with Fly {
/**
* defining defineMe function
*/
def defineMe = "I am a Pigeon"
}
/**
* AppMain class with main function
*/
object AppMain extends Application {
// penguin instance have on swim trait
var penguin = new Penguin
println(penguin.defineMe)
penguin.swim
// pigeon instance have all traits
var pigeon = new Pigeon
println(pigeon.defineMe)
pigeon.fly
pigeon.swim
}
Scala and Java Interoperability
This example shows how we can use scala program with java programs and vice versa.
- As we know the Scala classes also get compiled to .class file and generates the same bytecode as java class. Thus the interoperability is smooth between two languages.
Java Class
package com.tk.java;
import com.tk.scala.ScalaLearner;
/**
* The Class JavaLearner.
*/
public class JavaLearner {
private String firstName;
private String lastName;
public JavaLearner(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public void consoleAppender() {
System.out.println(firstName + " " + lastName + " is a java learner");
}
public static void main(String[] args) {
JavaLearner printJava = new JavaLearner("Kuldeep", "Singh");
printJava.consoleAppender();
// create instance of scala class
ScalaLearner printScala = new ScalaLearner("Dhruv", "Bansal");
printScala.consoleAppender();
}
}
Scala Class
package com.tk.scala
class ScalaLearner(firstName: String, lastName: String) {
/**
* Scala API prints message on console
*/
def consoleAppender() = println(firstName + " " + lastName + "i am in scala learner")
}
/**
* This Object is java representation of singleton object
* this piece of code will generate class file with name
* AppMain having singleton class AppMain having public
* static void main method
*/
object AppMain {
def main(args: Array[String]): Unit = {
var scalaLearner = new ScalaLearner("Kuldeep", "Singh");
scalaLearner.consoleAppender;
// import class in the scope of another class only
import com.nagarro.jsag.java.JavaLearner
// creating instance of java class file
var javaLearner = new JavaLearner("Dhruv", "Bansal");
javaLearner.consoleAppender;
}
}
##Performance comparison of Scala with Java The performance measurement we did bubble sort on revert order array with same code in Scala script and Java Class file. All measurements were done on an Intel Core i7-3720QM CPU 2.60 GHz using JDK7u7 running on Windows 7 with Service Pack 1. I used Eclipse Juno with the Scala plugin and mentioned above.
Java Bubble Sort Implementation
Java Program
package com.tk.scala;
/**
* The Class SortAlgo.
*/
public class SortAlgo {
/**
* Implementation of bubble sort algorithm.
*
* @param inputArray
* the input array
*/
public void bubbleSort(int inputArray[]) {
int i, j, t = 0;
int arryLength = inputArray.length;
for (i = 0; i < arryLength; i++) {
for (j = 1; j < (arryLength - i); j++) {
if (inputArray[j - 1] > inputArray[j]) {
t = inputArray[j - 1];
inputArray[j - 1] = inputArray[j];
inputArray[j] = t;
}
}
}
}
}
package com.tk.scala;
/**
* The Class AppMain.
*/
public class AppMain {
public static void main(String[] args) {
long start = System.currentTimeMillis();
consoleAppender("Sort algo start time: " + start);
Integer arraySize = 10000;
consoleAppender("Population array...");
int[] array = new int[arraySize];
for (int i = 0; i < arraySize; i++) {
array[i] = arraySize - i;
}
consoleAppender("Sorting array...");
SortAlgo sortAlgo = new SortAlgo();
sortAlgo.bubbleSort(array);
long end = System.currentTimeMillis();
consoleAppender("Sort algo end time: " + end);
consoleAppender("Total time taken: " + (end - start));
}
private static void consoleAppender(String strValue) {
System.out.println(strValue);
}
}
Scala program
package com.tk.scala
class SortAlgo {
// implementation of bubble sort
def bubbleSort(a: Array[Int]): Unit = {
var i:Int = 1;
for (i <- 0 to (a.length - 1)) {
for (j <- (i - 1) to 0 by -1) {
if (a(j) > a(j + 1)) {
val temp = a(j + 1)
a(j + 1) = a(j)
a(j) = temp
}
}
}
}
}
package com.tk.scala
/**
* Bubble sort singleton class with main method
*/
object BubbleSort {
def main(args : Array[String]) : Unit = {
// declaring and initiating local variable for performance measure
var startTime:Long = java.lang.System.currentTimeMillis();
println("Sorting start time: " + startTime)
val arraySize = 10000;
// declaring Integer array
var arry : Array[Int] = new Array[Int](arraySize)
println("Populating array...")
for(i<- 0 to (arraySize - 1)){
arry(i) = arraySize - i;
}
println("Sorting array...")
var algo:SortAlgo = new SortAlgo;
// calling sort API
algo.bubbleSort(arry)
var endTime:Long = java.lang.System.currentTimeMillis();
println("Sorting end time: " + endTime)
println("Total time taken:" + (endTime - startTime))
}
}
Comparison
See below table for performance metric s of above two programs:
Size | Scala | Java | |
---|---|---|---|
Time to populate Array | 100000 | 70 ms | 3 ms |
Time to Sort Array by Bubble sort | 100000 | 26187 ms | 12104 ms |
Time to populate Array | 10000 | 69 ms | 1 ms |
Time to Sort Array by Bubble sort | 10000 | 339 ms | 140 ms |
Conclusion
We have learned basics of Scala tried benchmarking it against Java. We found the Scala produce less verbose code but it is slower in certain cases in comparison to java.
This article is also supported by my friend Dhruv Bansal
References
- Official Website -http://www.scala-lang.org/
- http://www.scala-lang.org/node/25
- http://www.codecommit.com/blog/scala/roundup-scala-for-java-refugees
- http://www.tutorialspoint.com/scala/scala_lists.htm
- http://joelabrahamsson.com/learning-scala-part-seven-traits/
In the next article we will see how to build web applications using Scala.
#scala #java #introduction #language #comparison #technology