Appendix A

Quick Preview of Java

Scala has many of its roots in the Java programming language beyond compiling to the Java Virtual Machine (JVM) and having the ability to call on Java library functions. For this reason, it should not be too hard to pick up Java after you have learned Scala. This appendix is designed to help you in doing exactly that. To accomplish that goal, we will run through a number of different simple examples of Java code and look at the ways in which they are different from Scala code. Given that you are already familiar with Eclipse, this will be done using that platform. Simply switch to the Java perspective, which is the default for Eclipse, make a project, and try things out.1

A.1 Hello World

We will start with Java that same way we started with Scala, using the essential "Hello World" application. Here is what that code looks like in Java. It looks like a Scala application. In Java, there is no scripting model, nor is there an REPL. As such, this is as simple as it gets.

package javacode;


  
public class HelloWorld {
  public static void main(String[] args) {
  System.out.println("Hello World!");
 }
}

Just from this little example though, there are a number of things that are obviously different. First, Java does not infer semicolons. You have to type them. In this code we see one semicolon at the end of the package declaration and another at the end of the print statement.

Going into the class you see that it starts with the public keyword. Scala does not have a public keyword as that is the default visibility. Java also has keywords for private and protected visibility. In Java public visibility is not the default visibility. Instead, the default in Java is called package private. That is what we would get in Scala if we said private[javacode] because this class is in the javacode package. Java does not give you the fine grained control over visibility that Scala does, so the public, private, protected, and package private options are all you have.

In Java it is very strongly recommended that data members never be made public. Unlike Scala, you can not change a public data member into appropriate methods to include checking of values without breaking code. As such, the default for all data members should absolutely be private when you are coding in Java. Part of this is also the fact that method calls in Java always require parentheses and member data access never has them. So in Java, the syntax always tells you if you are using a method or a data member. Scala went the other way so that the implementation can be changed without breaking code.

The class declaration has curly braces after it. Curly braces in Java group code just like in Scala, but they are a group statement, not an expression. In Java, a code block using curly braces will not give you a value.

Looking inside the class at the one method, the declaration of main includes a number of differences as well. The first is the static keyword, which does not exist in Scala. Java does not have singleton objects. The closest approximation to them in Java is static data members and methods. The static keyword in Java implies that the thing being declared is associated with the class instead of being associated with the instances of that class. They are very much like the members of a companion object except that there is no companion object encapsulating them which reduces their flexibility a bit. The main method has to be static in Java for the same reason that they had to go in a singleton object in Scala. Without that, it could not be invoked without some class being instantiated first.

After the static keyword in another word we did not see in Scala, void. This is a type in Java that represents nothing. The equivalent of void in Scala is Unit. The difference is that there is no instance of void while there is an instance of Unit represented by (). Also not that void comes before the name of the method, not at the end after a colon as types did in Scala. All Java types precede the names they are associated with. One advantage of this is that Java does not need the val, var, or def keywords for those declarations. The type tells the language you are declaring something. The downside is that you have to specify a type. Java does not do type inference for you the way that Scala does.

After the method name, main, is String[] args. Based on your knowledge of Scala you should realize that args is the name of a formal parameter and you can figure out that String[] specified a type that is equivalent to the Scala type Array[String]. We will come back to the Java array syntax in a bit, but the short version here is that Java uses square brackets only for arrays, not type parameters, and you specify a type that is an array of another type by putting square brackets after the type. The formal argument shows again that the types in Java precede the names they are associated with.

Inside the main method is a single call to println. By default, there is nothing set up in Java to bring the println method into scope. Instead, you specify the full name, System.out.println. Breaking this down, System is a class in java.lang, which is imported by default. There is a static member in System named out that is a java.io.PrintStream, which has println methods for different types.

A.2 Arrays, Primitives, and More

The next example is a bit more significant. This creates and array of 1000 integers, fills it with the first 1000 prime numbers, then adds them up and prints the sum.

package javacode;


  
import static java.lang.System.out;


  
public class PrimeArray {
  private static boolean isPrime(int n) {
  for(int i = 2; i∗i<=n; ++i) {
  if(n%i==0) return false;
 }
  return true;
 }


  
  public static void main(String[] args) {
  int[] primes = new int[1000];
  int pos = 0; int i = 2;
  while(pos<primes.length) {
   if(isPrime(i)) {
   primes[pos] = i;
   pos++;
  }
   i++;
 }
  int sum = 0;
  for(int j=0; j<primes.length; ++j) {
  sum += primes[j];
 }
  out.println(sum);
 }
}

To shorten the call to System.out.println a bit, the file has a static import at the top. Normal imports in Java can only import the contents of packages. The static import also has the ability to import static members. Note that the Scala version does not distinguish between types of uses. Also, Java import statements need to be at the top of the file and they lack much of the flexibility of those in Scala. If you want to import all of the contents of a package in Java use instead of _.

The class in this file has two methods in it called isPrime and main. Both are static. The main method has to be static so that it functions as an entry point into an application. The isPrime method needs to be static here because only a static method can be called from another static method without instantiating a class to call it on. It also should be static because it does not use any information from any instance of the class.

Looking in the isPrime method shows a few more differences between Java and Scala. There are two more types that appear here, boolean and int. These should look familiar to you. They are just like what you are used to in Scala except for the fact that they start with a lowercase letter. You might have noticed this about the void type as well, though it is not true about the String. This is more than just a matter of capitalization. It has semantic implications as well. Java is not as object-oriented as Scala. The instances of the basic types in Java are not objects. They are called primitives and they do not have any methods. This is why their types start with lowercase letters. String is a class and instances of String are objects.

The for loop should stand out as another significant difference. The for loop in Scala is technically a for-each loop that runs through the contents of a collection. Java’s basic for loop is more of a dressed up while loop. In the parentheses there are three parts, separated by semicolons. The first part is an initializer where you set things up. This happens once, right when the loop is reached. If variables are declared there, as is the case in this example, that variable has a scope only through the loop.

The second part is a condition, just like what you would put in a while loop. It is pre-check and the loop will iterate until the condition is false. This is why the Java for loop can be described as a dressed-up while loop. The way in which the end case is determined is just like a while loop. The dressing is what comes before and after the semicolons around the condition.

The last part of what appears in the parentheses of a for loop is an iterator. This code happens after the body of the loop is evaluated and before the next condition check. In this case, the expression is ++i. This is a pre-increment of the variable i. The ++ operator in Java does an increment by 1. It can be placed before or after the variable. When it is before, the result of that expression is the incremented value. When placed after the expression the result is the value before the increment.

There is another type of for loop in Java which functions as a for-each loop. The syntax is for (type name:iterable), where type is the type in the collection, name is the variable name you want, and iterable is an object of type Iterable.

One last thing to note about the for loop is that it is never an expression. It never gives back a value. There is no equivalent to yield. The while loop in Java looks just like what you are used to in Scala.

The isPrime method also uses the return keyword. This is a valid usage in Scala, but you typically do not need it because every block is an expression with a value equal to that of the last statement in the block. In Java, blocks are not expressions, so every method that returns a value needs to specifically include a return statement at the end. If a return statement is reached inside the method, it will terminate the execution of that method and immediately jump back out to where it was called from.

The main method demonstrates Java’s array syntax. The primes variable has the type int[]. You can see the array itself is built using the new syntax. Inside of the while loop you can see that the indexing of the array is also done using square brackets, passing in the index you want to access. Arrays in Java are objects, so you can ask them how long they are using length. Note that length here is a data member. You know this in Java because there are no parentheses after it. The length of a String, however, is gotten with a method and must always have empty parentheses after it.

A.3 File Names and Interfaces

To illustrate a few more features of Java we will use another favorite example, the bank account. We begin by introducing a supertype for bank accounts.

package javacode;
public interface BankAccount {
  String getName();
  int getBalance();
}

This supertype is made using a Java construct called an interface. You can think of an interface as being like a trait that has no data members and where everything is abstract. Basically, an interface is a completely abstract supertype. An interface provides subtyping only, there is no code that goes into the subtypes. Java also only allows single inheritance of classes. This makes some things simpler as Java has no need to linearize virtual method resolution. The downside is that interfaces never have all that many methods as no one would want to ever implement an interface that forces them to write many tens of methods.

This interface will be inherited by a CheckingAccount class. Note that when inheriting from an interface in Java you use the implements keyword. When you inherit from a class you use the same extends keyword that you are used to from Scala. Multiple interfaces can follow implements and they are separated by commas.

package javacode;


  
public class CheckingAccount implements BankAccount {
  private final String name;
  private int balance = 0;


  
  public CheckingAccount(String n,int b) {
  name = n;
  balance = b;
 }


  
  @Override
  public String getName() {
  return name;
 }


  
  @Override
  public int getBalance() {
  return balance;
 }


  
  public boolean deposit(int amount) {
  if(amount>=0) {
  balance += amount;
  return true;
 } else {
  return false;
 }
 }


  
  public boolean withdraw(int amount) {
  if(amount>=0 && amount<=balance) {
  balance -= amount;
  return true;
 } else {
  return false;
 }
  }
}

There are many things in this class that are worth noticing. Before looking at the details though, we should note something that is not at all obvious here. The BankAccount interface is located in a file called "BankAccount.java". The CheckingAccount class is in a separate file called "CheckingAccount.java". In Scala it was recommended that separate class, trait, and object declarations be put in separate files with names that match. In Java, this is not just recommended, it is required. There can be only one top-level public declaration per file in Java, and its name must match the name of the file.

So what are some of the differences between this code and what you would have written in Scala? For one thing, the name member is preceded by the final keyword. In Scala, final means that something can not be overridden in a subtype. When applied to a method, it has that same meaning in Java. However, when used in front of a variable declaration, it means that the value of that variable can not be changed after it is set. A final variable in Java is like a val declaration in Scala. Without final, it is like you are using var.

There is something else worth noting about name, it is not given a value. In Scala, any member without a value is considered abstract. This is not the case in Java. You can declare variables either locally or as class members without providing an initial value. For local variables, Java will check that they are not used before initialization and give you an error if that happens. For member variables there is no error. Instead, they are given a default value. For primitives the default is 0, 0.0, or false, depending on the exact type. For object types, typically called reference types in Java, they are given the value of null. This is a very common source of errors in Java and that is one of the reasons Scala forces you to initialize variables.

A.4 Constructors and @Override

With this example it also starts to become obvious that there are no arguments to the class. Argument lists are not required for Scala, but in this situation they would clearly have been useful. There are no argument lists for classes in Java. To get information into an object when it is instantiated in Java, you write constructors. A constructor is a method that gets called when an object is instantiated. By default, Java creates a constructor that takes no arguments. If you include any constructor of your own, the default one is no longer created for you. A constructor looks like a method except that it has no return type, not even void, and the name matches the name of the class. In CheckingAccount you can see that there is a constructor directly after the two lines declaring the member data. This constructor takes initial values for the member data and sets it.

There are some things worth noting here. First, writing a little class in Java with member data that can be set at construction is much more verbose in Java than it is in Scala. The class needs to contain declarations of the data members and a constructor that sets them instead of just listing them with val or var in an argument list. One could argue that the payoff of this is that the syntax for multiple constructors is a bit cleaner.

After the constructor are the two methods required by the supertype along with two others for doing deposits and withdraws. These should all be fairly straightforward at this point. The only thing really new is the @Override annotation. Scala made override a keyword in the language. Java did not do that originally, but added the annotation in later. This is not required in Java, but for the same reasons it is required in Scala, it is strongly recommended that you include it in Java. Eclipse will add it for you if you have it put in methods required by a supertype.

A.5 Generics and Polymorphism

To make the accounts useful, they need to be put into a bank. This is something that could involve a large amount of code, but we will stick to a very short example to demonstrate the basic concepts. Here is simple Bank class that keeps track of accounts using a Java collection.

package javacode;


  
import java.util.∗;


  
public class Bank {
  private List<BankAccount> accounts = new ArrayList<BankAccount>();


  
  public void makeNewCheckingAccount(Scanner sc) {
  System.out.println("Who is the new checking account for?");
  String name = sc.next();
  System.out.println("What is the starting balance in cents?");
  int bal = sc.nextInt();
  accounts.add(new CheckingAccount(name,bal));
 }


  
  public static void main(String[] args) {
  Scanner sc = new Scanner(System.in);
  Bank bank = new Bank(); bank.makeNewCheckingAccount(sc);
  for(BankAccount ba:bank.accounts) {
  System.out.println(ba.getName()+" "+ba.getBalance());
 }
 }
}

The accounts are specifically stored in a java.util.List. The closest equivalent to this in Scala is the mutable.Buffer. Like the Buffer, the List is implemented using both an array and a linked list. You can see here that we have gone with the array-based implementation.

The fact that Java used square brackets for arrays means that something else must be used for type parameters. These are called generics in Java and they are put inside of angle braces, the characters we typically read as less than and greater than. As with Scala, you can make Java classes or methods generic. The generic type is typically inferred for methods, but not for classes.

If you want to make a collection or just a reference that can hold "anything" in Java, the common supertype is Object. Technically, Object is equivalent to AnyRef. The fact that primitives are not objects means they are not instances of any class. They are not involved in supertype/subtype relationships. To get around this, Java includes wrapper types like java.lang.Integer and does something called autoboxing to wrap up primitives in a way that makes life easier on the programmer. Technically Scala was doing this same thing for efficiency, but it hides the primitives from the programmer completely.

A.6 Lacking Functional Aspects

It was mentioned above that Java is not as object-oriented as Scala. As of Java 7, Java is not functional at all. There are no function literals in Java. Functions are not objects and can not be passed around freely. There is no pass-by-name semantics in Java. There are no curried methods and you do not really have higher-order methods. The closest thing to a function literal in Java is an anonymous inner class that inherits from an interface with a single method.

Java 8 is likely to change some of this as function literals are being added to Java in the form of lambda expressions. It isn’t yet clear what impact that will have on making the language as a whole more functional. It is likely that methods like map and filter will start to appear in the standard Java collection library, but they are not present yet.

A.7 Much More

There is a lot more to Java than what has been presented here. This has been shown here. In some ways, Java is fairly simple and straightforward, but in other ways it is not. The language specification for Java is more than three times longer than that for Scala and Java has significantly more keywords than Scala. Fortunately, there are many resources you can use to help you learn Java that are available online along with many books on the subject. What is more, through exploring the Java application programming interface (API) to use with Scala programs, you already have something of a head start on the learning process.

1 The Eclipse plug-in for Scala will allow you to put Java code into a Scala project for a mixed language project. Technically that is what was done when writing this appendix. If you want to learn Java though you should probably make a clean break.

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

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