Java Code compared to Scala Code (2) - A Simple Class

Feb 15, 2011 10:33 · 844 words · 4 minutes read Scala Java

A common task: a simple class representing some entity your system deals with. It is more or less a bean, but also needs proper equals and hashCode implementations to be used in collections (also this makes unit testing easier). Java being an object-oriented language, this should be right up it’s alley. In our example we have a user that we want to represent. Our user has a first name, last name, email and password, where the password is another class that takes care of hashing, salt, etc. Let’s look at the two implementations:

The Original in Java

public class User {
private String firstName;
private String lastName;
private String email;
private Password password;

public User(String firstName, String lastName, 
        String email,  Password password) 
{
    this.firstName = firstName;
    this.lastName  = lastName;
    this.email     = email;
    this.password  = password;
}

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

public Password getPassword() {
    return password;
}

public void setPassword(Password password) {
    this.password = password;
}

@Override
public String toString() {
    return "User [email=" + email + ", firstName=" + firstName
       + ", lastName=" + lastName + "]";
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((email == null) ? 0 : email.hashCode());
    result = prime * result + ((firstName == null) ? 0 : firstName.hashCode());
    result = prime * result + ((lastName == null) ? 0 : firstName.hashCode());
    result = prime * result + ((password == null) ? 0 : password.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    User other = (User) obj;
    if (email == null) {
        if (other.email != null) return false;
    } else if (!email.equals(other.email))
        return false;
    if (password == null) {
        if (other.password != null) return false;
    } else if (!password.equals(other.password))
        return false;
    if (firstName == null) {
        if (other.firstName != null) return false;
    } else if (!firstName.equals(other.firstName))
        return false;
    if (lastName == null) {
        if (other.lastName != null) return false;       
    } else if (!lastName.equals(other.lastName))
        return false;
    return true;
}           
}

The Scala version

case class User(var firstName:String, var lastName:String, 
                var email:String, var password:Password) 

My 2 ¢

I wrote this for a friend of mine who claimed Java would be easier to read and therefore better suited for beginners or less experienced programmers. What do you think is better to understand for a beginner?

To make things interesting, the Java version has a subtle bug in it. I have spent wasted a lot of time in my programming career on finding bugs like it, so I thought I would throw one in for good measure. Did you see it?

I know that by using guava or some apache stuff the equals & hashCode implementations could be done in a less horrible way, but my point was to show what you can do with the language itself and it’s core API. Also, modern IDEs create those methods for you with the click of a button, so it is likely that most people will use that feature because it is easy. But what the IDEs do not do:

  • Keep it up to date if new members are added.
  • Warn you if someone has modified the auto-generated code for some reason and you simply recreate it automagically, erasing your colleagues (crucial) code

For those new to Scala, you might wonder how the Scala class can do everything the Java class does, so here are the explanations:

Equals & Hash Code

equals & hashCode are autogenerated correctly because it is a case class.

Constructors & Member Declarations

The declaration of the class is also a constructor, the keywords val/var declare the constructor args to be members.

Getters & Setters

Getters & setters are not necessary, as we need no special getter & setter behavior. We do not need special behavior in the Java version either, but we might need it in the future, so we need to make everything private and add accessor methods. Otherwise client code that uses the class is wired to using user.firstName, not user.getFirstName() and we need to refactor it if we introduce accessors later.

If, for example, the Scala code needs to hide a member, we can simply add accessors later. The API of the class stays the same. This would be a getter and setter for the first name:

def firstName = _firstName
def firstName_=(f:String) {
    //Make sure we get no Alberts
    if (f == "Albert"){
        throw new SpaghettiCodeException();
    }
    _firstName = f
}

The API to get/set the first name would still be user.firstName and user.firstName = "Hans", all we need is a recompile, not a refactoring.

The irony with the Java code: the time you waste with useless typing could be spent enjoying a nice cup of Java!