Skip to content

Some modern (but older) Java concepts

About

This article covers some newer Java concepts required for the course Concepts for Concurrent, Parallel and Distributed Programming at Ulm University.

Optional <T>

To prevent the usage of Nullpointers (and thus NullPointerExceptions), you can use the Optional construct.

import java.util.Optional;
//...
    {
        //...
        var result = test_optional(false);

        // or check for opposite with result.isEmpty()
        if (result.isPresent()) {
            System.out.println("value present: " + result.get());
        } else {
            System.out.println("value not present, can't call result.get()");
            // result.get() would throw NoSuchElementException
        }

    }

    public static Optional<String> test_optional(boolean return_empty) {
        if (return_empty) {
            return Optional.empty();
        } else {
            var test = "optional value";
            return Optional.of(test);
            // if value can be null, use Optional.ofNullable(...)
        }
    }
//...

Further reading: Guide To Java 8 Optional

var keyword

If you have a long datatype with many generics, it might be tedious to repeatedly write the datatype for your variable declaration. With the var keyword, the compiler can figure that out with Type Inference.

// getValueFromDatabase() returns String
var myMap = new HashMap<String, List<String>>();

// other scenario where type inference is used
Map<String, List<String>> myMap = new HashMap<String, List<String>>();
Map<String, List<String>> myMap = new HashMap<>();

Further reading:

Lambda expressions

Source for this Snippet:

// Concise
n -> System.out.print(n)

// Expanded
(String n) -> System.out.print(n)

// Verbose
(String n) -> { System.out.print(n); }

Example usage:

// map function to list
import java.util.ArrayList;
import java.util.List;
ArrayList<Integer> numbers = new ArrayList<>(List.of(1, 2, 3, 4, 5));
numbers.forEach((num) -> System.out.println(num));


// Store in a variable
import java.util.function.Consumer;
Consumer<String> myLambda = (n) -> System.out.println(n);
myLambda.accept("test");

Further reading:

new switch syntax

A switch case can now be written with ->. The break keyword is not required anymore:

// ...
var b = switch (a) {
    case 0 -> 1;
    default -> {
        x = a*42;
        yield x;
    }
};
// ...

record keyword

With records, constructors and getters are automatically generated by the compiler. However, the values of the record are immutable, i.e. after the values are passed to the constructor, they can't be changed again (except for creating a new record instance). To use records, simply add the record keyword to a class:

public record Person(String name, String address) {
    // Public Constructor with name, address is automatically generated
    // Getter Methods are also automatically generated
}

Further reading:

sealed keyword

Sealed classes and interfaces restrict which other classes or interfaces may extend or implement them1.

// only Car and Truck are allowed to implement Service
public sealed interface Service permits Car, Truck {
    //...
}

// -----------------------------------------------------------------------------

// only Car and Truck are allowed to inherit from Vehicle
public abstract sealed class Vehicle (extends ...) (implements ...) permits Car, Truck {
    //...
}
// the permitted subclass can then be defined final or non-sealed to
// prevent/allow further extension.

Further reading: