Java 16 marked a significant update with Records and jpackage becoming standard features. It introduced support for Unix Domain Socket communication for inter-process communication. Elastic metaspace improved memory management, and the ZGC collector received further enhancements.
March 2021
Java 16 marked a significant update with Records and jpackage becoming standard features. It introduced support for Unix Domain Socket communication for inter-process communication. Elastic metaspace improved memory management, and the ZGC collector received further enhancements.
Immutable data classes with minimal boilerplate
// Basic record
public record Point(int x, int y) {}
// Record with validation
public record Person(String name, int age) {
public Person {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("Name cannot be null or blank");
}
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
}
// Additional methods
public boolean isAdult() {
return age >= 18;
}
}
// Record with custom constructor
public record Temperature(double celsius) {
public Temperature(double fahrenheit, boolean isFahrenheit) {
this(isFahrenheit ? (fahrenheit - 32) * 5.0 / 9.0 : fahrenheit);
}
public double fahrenheit() {
return celsius * 9.0 / 5.0 + 32;
}
}
// Usage
var point = new Point(10, 20);
var person = new Person("John", 25);
var temp = new Temperature(100, true); // 100°F
System.out.println(point.x()); // 10
System.out.println(person.isAdult()); // true
System.out.println(temp.celsius()); // 37.78Java Records provide a concise way to create immutable data classes with automatic generation of constructor, getters, equals(), hashCode(), and toString() methods. Records are perfect for modeling data transfer objects (DTOs) and value objects with minimal boilerplate code.
// 1. Basic Record Declaration
public record Point(int x, int y) {}
// 2. Record with Compact Constructor
public record Person(String name, int age) {
public Person {
if (age < 0) throw new IllegalArgumentException("Age cannot be negative");
}
}
// 3. Record with Custom Methods
public record Circle(double radius) {
public double area() { return Math.PI * radius * radius; }
public double circumference() { return 2 * Math.PI * radius; }
}
// 4. Record with Static Methods
public record Temperature(double celsius) {
public static Temperature fromFahrenheit(double f) {
return new Temperature((f - 32) * 5.0 / 9.0);
}
public double fahrenheit() { return celsius * 9.0 / 5.0 + 32; }
}
// 5. Record with Nested Records
public record Address(String street, String city) {}
public record Employee(String name, Address address) {}
// 6. Record with Generic Types
public record Pair<T, U>(T first, U second) {
public static <T, U> Pair<T, U> of(T first, U second) {
return new Pair<>(first, second);
}
}Inter-process communication using Unix domain sockets
import java.nio.channels.SocketChannel;
import java.nio.channels.ServerSocketChannel;
import java.net.UnixDomainSocketAddress;
import java.net.StandardProtocolFamily;
import java.nio.ByteBuffer;
import java.nio.file.Path;
// Server side
Path socketPath = Path.of("/tmp/java-socket");
UnixDomainSocketAddress address =
UnixDomainSocketAddress.of(socketPath);
try (ServerSocketChannel serverChannel = ServerSocketChannel.open(
StandardProtocolFamily.UNIX)) {
serverChannel.bind(address);
try (SocketChannel clientChannel = serverChannel.accept()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = clientChannel.read(buffer);
// Process received data
buffer.flip();
String received = new String(buffer.array(), 0, bytesRead);
System.out.println("Received: " + received);
}
}
// Client side
try (SocketChannel clientChannel = SocketChannel.open(
StandardProtocolFamily.UNIX)) {
clientChannel.connect(address);
String message = "Hello from client";
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
clientChannel.write(buffer);
}