loading...

Back and forth from Scala to Java

gerbrandvd profile image Gerbrand van Dieyen ・5 min read

For over two years I've programmed nearly exclusively in Scala on the backend, while using mostly JavaScript and TypeScript on the frontend. Before that I mostly used Java for over 15 years, as well as a few other programming languages
Since a month I use Java, Java 8 even, on an assignment, and I thought I shared my experience.
The reason I use Java again, because the client uses Java and more broadly, I wondered how easy it would be to switch back if needed. After all I claim to be programming-language agnostic

First, going back wasn't as hard as I thought it was, it all came back to me pretty quickly. Of course I'd need to add ; and some more superfluous code, but that's doable.

Lambda's

I use Java 8, which is the first Java version to feature lambda's. I don't think I could bear a language without. I use lambda's heavily, probably more than people who'd never used a programming language.
Scala uses =>, Java uses ->, but that's ok.

Mutable data

Just as in Scala, mutable data-structures can lead to unpredictable behavior. In the Scala world people are by now pretty used to using immutable data-structures.
In the Java world, rather then thinking about how to transform data correctly, people still deliberate about anthropomorphic questions like what responsibilities an object has and how a Employee class relates to an employee in the real world.

Option

Java 8 introduced the Optional class, so there's no excuse for having NullPointerExceptions in your code (well, except when using older code and libraries).
Java 8 Optional has a map method. Annoyingly, it's orElse method of Option returns the actual value type instead of the value wrapped in an Optional, so you can't chain an orElse. I have no idea what the language designers were thinking. Well, as alternative I could use map, but that's a bit less readable:

      Optional<String>  firstName=Optional.of("John");
      Optional<String>  lastName=Optional.empty();
      Optional<String> name = firstName.map(Optional::of).orElse(lastName);

Fortunately, Java 9 introduced or.

Optional and streams

Also, Java's Optional can't be used as Iterable, while Scala's Option can. Allowing to treat Option as a collection of zero or one values helped me better understanding what an Option is and how you could use it beyond the isPresent() method.
Converting an Option to a Stream shouldn't be too hard:

    public static <T> Stream<T> stream(Optional<T> option) {
        return option.map(Stream::of).orElse(Stream.empty());
    }

Which will then allow me to write:

      Optional<String>  firstName=Optional.of("John");
      Optional<String> middleName=Optional.empty();
      Optional<String>  lastName=Optional.of("Doe");

      ...
   private String toName(Optional<String> firstName, Optional<String> middleName, Optional<String> lastName) {
      return Stream.of(
              stream(firstName),
              stream(middleName),
              stream(lastName))
              .flatMap(Function.identity())
              .collect(Collectors.joining(" "));
   }

That doesn't look so concise anymore, but arguably better than nested if else blocks.

Try catch finally and Either

In Java 8, when you use a resource that implements the Closeable interface working, a finally block to close the resource is no longer necessary. That's pretty nice:

    public String readMe() throws IOException {
        try(BufferedReader in = new BufferedReader(new FileReader("some file.txt"))) {
            return in.readLine();
        }
    }

At least when an exception is thrown, the resource is closed. What I greatly miss, is a Try class, Either or something similar so no exception is thrown by the method at all. There are a few libraries that do add something like Either, like functionalj, but of course these are non-standard so a bit harder to introduce at project.

Beyond the limits of imperative OO: annotations, aspects and reflection.

As is pretty common, Spring is also used to extend Java. Spring is based on the principle of aspect- or plugin-oriented programming and heavily relies on bytecode-enhancement and reflection to extend the language Java. In practice this means you use either annotations or config files.
The biggest disadvantage: everything is applied at runtime, e.g., when your application runs.
In Scala, the language itself is flexible enough using pattern matching, implicits, macros and other language constructs.
Scala pattern matching does use reflection in some cases, but most errors are catched compile time rather then runtime. And despite people complaining about implicit, having an error during compilation because you forgot to import an implicit is a lot easier to handle than an error that occurs when running your software because some configuration is wrong, or something fails during reflection.

Spring will give you pretty good errors when having a wrongly applied annotation, and IntelliJ does have good support for Spring. So most of the times you'll get reasonable descriptive warnings or errors for missing beans, wrong spring-configuration, etc, which makes Spring almost feel being part of the language. And it still feels cumbersome, if only because your code is cluttered with annotations.

Lombok, case classes

Scala introduced case classes, which allows you to write value based classes without a lot of boilerplate - or mistakes like accidentally committing a property in equals or hashCode.

Java by default doesn't. I'm very glad someone created Lombok and it seems well accepted.

import lombok.Value;

@Value
public class Employee {
    String firstName;
    String middleName;
    String lastName;
    long employNumber;
}

You can't do everything you could do in Scala, like pattern matching on a case class, and unlike Scala there's still a difference between methods and properties in Java.
But it's a whole lot better then generated equals, toString and get'ter methods.

IDE support for Lombok is very good, so you hardly notice you're using language extensions.

Conclusion

Switching back and forth from Scala to Java is doable, but I certainly wouldn't want to go back indefinitely. The Scala world is still thriving. Java is bearable, but Scala makes programming doable.

Posted on by:

gerbrandvd profile

Gerbrand van Dieyen

@gerbrandvd

Software Engineer, with strong preference for functional programming. 20 years experience in professional (e.g. paid) programming.

Discussion

markdown guide
 

Hi,
I suggest you to use Vavr. I use it extensively for all Java projects.
I also prefer Immutables over Lombok, but it's just about the personal taste.