Records in Java (JEP 359, preview)

Records in Java look very promising to me and a great addition to the language. The ceremony of creating pure data holder classes will be well know to any Java developer.

Sometimes we just create a class to transport some data from A to B. Most of the times we don’t even care about object equality or an efficient hash code algorithm. Nonetheless, the amount of code you (usually) generate is quite a bit. I’d go so far to say that the need to create classes for everything sometimes takes me out of the flow.

Take this simple example:

public class Person {
  private String name;
  private String firstname;
  private String address;
 
  public Person(String name, String firstname, String address) {
    this.name = name;
    this.firstname = firstname;
    this.address = address;
  }

  public String getName() {
    return this.name;
  }
  
  public void setName(String name) {
    this.name = name;
  }

  // ... all the other getters and setters, hashCode() and equals(), toString()

With records we would be able to declare a pure data holder structure way easier. And the best thing: it takes care about equality, hash code generation and a proper string representation (toString())

record Person(String name, String firstname, String address) {};
Image result for meme unbelievable

Yep, that one line expresses the same thing as the class above.

As a seasoned Java developer you may know that you can declare a class locally as part of a method. I don’t think this is common practice, but with records I could imagine that we can solve several problems in a very elegant way by just declaring a local record.

Try it out today

You can download early access builds from https://jdk.java.net/14/ (just unzip it somewhere you find it again). No comfort version, without any IDE – it’s fun to use these commands from time to time. Just keep in mind to enable the preview features:

Compile

c:\Dev\jdk-14\bin\javac -source 14 –enable-preview YourClass.java

Run

c:\Dev\jdk-14\bin\java –enable-preview YourClass

Personal opinion

I like it. But I feel like I’m saying this for every new Java feature. I do have some concerns about pattern matching and switch expressions as you can read in my other posts. But I don’t see a lot of trouble with this one coming!

Switch Expressions in Java (JEP 361)

With Java 14 we will get a new feature that simplifies the switch statement. It will provide a new and clearer way to write switch statements and in addition allows us to use switch as an expression yielding a value.

New Syntax

Forget about break! No fall through anymore – simple and concise.

switch (day) {
    case MONDAY             -> System.out.println("Fully motivated!");
    case TUESDAY, WEDNESDAY -> System.ouFt.println("Get this done!");
    case THURSDAY, FRIDAY   -> System.out.println("Almost done!");
    case SATURDAY, SUNDAY   -> System.out.println("Party time!");
}

Today you would write something like below. Don’t miss the breaks!

switch (day) {
   case MONDAY:
       System.out.println("Fully motivated!");
       break;
   case TUESDAY:
   case WEDNESDAY: 
        System.ouFt.println("Let's get this done!");
        break;
   case THURSDAY:
   case FRIDAY:   
       System.out.println("Almost done!");
       break;
   case SATURDAY:
   case SUNDAY:
       System.out.println("Party time!");
}

Switch Expressions

This is really cool. Now we can asisgn the result of a switch expression to a variable.

String workingDay = switch(day) {
    case 1,2,3,4,5 -> "yes";
    case 6,7 -> "no";
    default -> "don't know";
};

This is easy to read and allows us to simplify our code. Maybe until now you used nested conditional operators (!!) or you introduced a little helper method with return statements.

If you need an actual block to calculate the result of the expression, there is a new keyword you can use for that purpose: yield

String workingDay = switch(day) {
    case 1,2,3,4,5 -> "yes";
    case 6,7 -> "no";
    default -> {
       String defaultAnswer = calculateDefaultAnswer();
       yield defaultAnswer;
    }
};

You can also use the legacy switch syntax and form expressions using the yield keyword.

int result = switch (s) {
    case "Foo": 
        yield 1;
    case "Bar":
        yield 2;
    default:
        System.out.println("Neither Foo nor Bar, hmmm...");
        yield 0;
};

It’s an expression baby

Image result for coding meme

Yes, you can drive your co worker crazy by building complex and inlined switch expressions. It works – I tried it.

public static boolean isWorkingDay(String day) {        
    if ("yes".equals(switch (day) { case "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" -> "yes"; case "Saturday", "Sunday" -> "no"; default -> "dont' know";})) {
        return true;
    } else {
        return false;
    }
}

Try it out today

You can download early access builds from https://jdk.java.net/14/ (just unzip it somewhere you find it again). With Java 14 this is not a preview feature anymore, so you can just start to use the new switch expressions.

Personal opinion

In short: I really like it. I think it makes a lot of sense. Having the privilege to also teach classes in programming I can say that the intention of the programmer when using the switch statement was always a different one – always.

In addition using switch as an expression provides new ways also for a seasoned programmer to simplify their code. Have you ever seen those nested tenary conditional operators?

One downside I see is developers thinking that it is cool to inline switch expressions and combine them to more complex expressions that no one will ever touch again.

Image result for i can do it meme

Pattern Matching for instanceof (JEP 305)

Finally with Java 14 we get a (preview) feature I had on my wishlist for a long time. It eliminates the need to first test an object via instanceof operator and then (and I asusme it is the 90% case) cast it to exact that class in order to do something with it.

Here is the example directly taken from the JEP site:

if (obj instanceof String s) {
    // can use s here
} else {
    // can't use s here
}

Before we we had to write something like:

if (obj instanceof String) {
    String s = (String) obj;
} else {
    
}

But it gets even better

The binding variable that is introduced by the instanceof operator is not only accessible in the actual true block, but also in the logical extension of the boolean expression. I don’t know how to describe it in a better way.

if (obj instanceof String s && s.contains("hello")) {
  System.out.println("It contains the magic word!");
}

On the other hand this will not work and if you think it through a bit it also makes sense.

if (obj instanceof String s || s.contains("hello")) { // won't work!
  System.out.println("It contains the magic word!");
}

Try it out today

You can download early access builds from https://jdk.java.net/14/ (just unzip it somewhere you find it again). No comfort version, without any IDE – it’s fun to use these commands from time to time.

Code

package ch.christianmenz.java14;

public class PatternMatching {
    public static void main(String[] args) {
        Object obj = "hello world";
        if (obj instanceof String s) {
            System.out.println(s.length());
          }
    }
}

Compilation

C:\Users\chris\Documents\Java14\src>c:\Dev\jdk-14\bin\javac -d . -source 14 –enable-preview ch\christianmenz\java14\PatternMatching.java

It is important that you pass the source and the –enable-preview parameters.

Running

Running is also quite simple (note you don’t have to use pacakges as I did, I just did it for the nostalgic feeling).

C:\Users\chris\Documents\Java14\src>c:\Dev\jdk-14\bin\java –enable-preview -cp . ch.christianmenz.java14.PatternMatching

Extra: without manual compilation

If you read about this Java 11 feature, you might wonder if you could also use these preview features: yes you can! Just note you have to pass a double dash this time for the source parameter (I guess because of reasons ;-)).

C:\Users\chris\Documents\Java14\src>c:\Dev\jdk-14\bin\java –enable-preview –source 14 ch\christianmenz\java14\PatternMatching.java

Personal opinion

I’m a bit ambivalent about this feature. I certainly like that some boilerplate code can be eliminated. On the other hand the use of this language construct in combination with more complex expressions might lead to more misunderstandings and harder to understand software. Also keep an eye on this draft JEP, which aims to extend pattern matching to the switch statement: https://openjdk.java.net/jeps/8213076

Launch Java Programs Without Compilation (JEP 330)

Since Java 11 we can run Java programs directly from the command line without the need to manually compile them first. Frankly speaking I don’t know if this is a feature I will ever use in my daily work as a developer. But it could be useful to learn Java and provides an easy way to just get started.

Best read http://openjdk.java.net/jeps/330 to learn more about the motivation behind this feautre.

Running .java File

Simply run java HelloWorld.java on your command line and it will compile the class into memory and run it from there.

  
public class HelloWorld {

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

Passing Parameters

You can pass parameters as you normally would when starting your Java program:
java HelloWorld.java Chris

  
public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello " + args[0]);
    }
}

Different Filename

Maybe you don’t want to name your file HelloWorld.java but just hello.j. This is also possible but you need to pass an additional parameter. java –source 11 hello.j

In the example above I just renamed the file and ran it again.

Shebang Files

In addition to just launching Java files direclty you can also add a shebang to the file and execute it directly as a script on Unix like systems (of course you can also use Cygwin or some similar tool on Windows). I just used the Git Bash for the example:

#!java --source 11  
public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello " + args[0]);
    }
}

Java Collections Static Factory Methods

With Java9 we finally get an easy way to construct collections. I think the map is one that I will be using  quite often. Now I can write:

Map<String,String> lookupMap = Map.ofEntries(
        entry("a", "A"),
        entry("b", "B"),
        entry("c", "C"));

Instead of:

Map<String, String> lookupMap = new HashMap<>();
lookupMap.put("a","A");
lookupMap.put("b","B");
lookupMap.put("c","C");

Java 8 default methods

Why

OK, so interfaces can now provide a default implementation. This makes sense if you want to be able to add new methods to your interface without breaking existing implementations. Oracle uses default methods quiet extensively (see java.util.Collection).

Simple example

public class SimpleExample {
    
    interface Interface1 {
        
        default void test() {
            System.out.println("-- default test");
        }     
        
        default void test2() {
            System.out.println("-- default test2");
        }
    }
    
    static class Implementation1 implements Interface1 {
        
        public void test2() {
            System.out.println("my own implementation");
        }                      
    }
    
    public static void main(String[] args) {
        Interface1 if1 = new Implementation1();
        
        if1.test();
        if1.test2();
    }   
}

Guess what the program will output.

-- default test
my own implementation

Spring Boot Health Checks

Spring Boot brings along some cool “production ready” features. Among them are the health checks. They are a great way to give you a quick overview about the system state. Is the database up and running, is my disk running out of space?

Getting started

Having a Spring Boot application already setup you just have to add the dependency for the Spring Boot Actuator.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

This will add several useful endpoints to your application. One of them is /health. When you start your application and navigate to the /health endpoint you will see it returns already some data.

{"status":"UP","diskSpace":{"status":"UP","free":7537176576,"threshold":10485760}}

Add a custom health check

Adding a custom health check is pretty easy. Just create a new Java class, extend it from the AbstractHealthIndicator and implement the doHealthCheck method. The method gets a builder passed with some useful methods. Call builder.up() if your health is OK or builder.down() if it is not. What you do to check the health is completely up to you. Maybe you want to ping some server or check some files.

@Component
public class SomeServiceHealthCheck extends AbstractHealthIndicator {

  @Override
  protected void doHealthCheck(Health.Builder bldr) throws Exception {
    // TODO implement some check
    boolean running = true;

    if (running) {
      bldr.up();
    } else {
      bldr.down();
    }
  }
}

This is enough to activate the new health check (make sure @ComponentScan is on your application). Restart your application and locate your browser to the /health endpoint and you will see the newly added health check.

{"status":"UP","someServiceHealthCheck":{"status":"UP"},"diskSpace":{"status":"UP","free":7536922624,"threshold":10485760}}

Add a better view

For a quick overview the health checks are great, but no one from your operating team will love reading through the JSON result of the /health endpoint. Better create some view and present the data in a much more human readable way. I personally like the apporach jHipster has implemented for their health checks.

healthcheck

Conclusion

Personally speaking Spring Boot is the right step forward for the Spring framework. The production ready features offered, especially the health checks, are great to quickly locate connectivity issues and can give you an overall better feeling in production environments where you might not be able to analyze issues quickly due to access restrictions.