Java Releases

Java 10

Local Type Inference

public void printName(String firstName, String lastName) {
  var fullName = String.format("%s %s", firstName, lastName);
    System.out.println(fullname);
}

Java 11 (LTS)

Local Type Inference for Lamda

(var firstName, var lastName) -> firstName + lastName;

Java 14

Switch Expression w/ Return or Yield

Switch expressions can now return values.

switch (day) {
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY: -> return "weekday";
    case SATURDAY, SUNDAY: -> return "weekend";
    default: -> throw new Exception("Not a valid day"); 
}

Yield keyword is used when a code block is defined.

String dateCategory = switch (day) {
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY: -> "weekday";
    case SATURDAY, SUNDAY: -> "weekend";
    default: -> {
        int len = day.length();
        yield len % 2 == 0 ? "weekday" : "weekend";
    } 
}

Helpful NullPointerException Message

Exception in thread "main" java.lang.NullPointerException:
     Cannot assign field "age" because "author" is null

Java 15

Text Blocks

String text = """
  This is my long text block.
  """;

Java 16

Pattern Match for instanceof

// before
if (obj instanceof String) {
  String s = (String) obj;
  ...
}

// now
if (obj instanceof String s) {
  ...
}

Records

Records simplify the creation of immutable POJOs. They act almost like classes but you can’t subclass them.

record Key(String id, String name) {}

Java 17 (LTS)

Sealed

The sealed keyword on a class decleration allows you to restrict which classes can subclass the class being declared.

public abstract sealed class Human
  permits Male, Female { ... }

Java 21 (LTS)

Pattern Matching on Instance Type

String formatted = switch (o) {
    case Integer i when i > 10 -> String.format("a large Integer %d", i);
    case Integer i             -> String.format("a small Integer %d", i);
    case Long l                -> String.format("a Long %d", l);
    default                    -> o.toString();
};

Record Pattern Matching w/ Deconstruction

if (r instanceof ColoredPoint(Point2D(int x, int y), Color c)) {
  // work with x, y, and c
}

Virtual Threads

Virtual threads solve the problem of blocking I/O operation making threads idle. Blocking operations will now release the thread so that the thread can work on something else while the operations remains blocking. Once the operation is unblocked, it rejoins the queue of waiting tasks to be worked on.

// With OS threads, this would be very problematic
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            System.out.println("" + i);
            return i;
        });
    });
}

Leave a Reply