swipe ??
swipe ??
You can find more details and the latest version of this PDF at www.happycoders.eu/java-versions.
If a class name is ambiguous, such as Date, then the class must be imported directly (i.e., with import java.util.Date or import
java.sql.Date). In JShell and implicitly declared classes, the java.base module is imported automatically.
try { map
number = Integer.parseInt(string); .computeIfAbsent(key, _ -> new ArrayList<>())
} catch (NumberFormatException _) { .add(value);
System.err.println("Not a number");
}
switch (object) {
case Byte _, Short _, Integer _, Long _ -> System.out.println("Integer number");
case Float _, Double _ -> System.out.println("Floating point number");
default -> System.out.println("Not a number");
}
Thanks to "region pinning" added in Java 22, the G1 Garbage Collector can now "pin" a memory region containing such an object,
i.e., not move the objects it contains to another memory address, so that garbage collection no longer has to be paused
completely.
Another interface is SequencedMap, which is implemented by LinkedHashMap, TreeMap, and ConcurrentSkipListMap and provides
the methods firstEntry(), lastEntry(), pollFirstEntry(), pollLastEntry(), putFirst(...), putLast(...), and reversed().
a += b;
a = a + b;
Most Java developers will say: There is none. But that is wrong. If, for example, a is a short, and b is an int, then the second line
will result in a compiler error:
That is because a + b results in an int, which may not be assigned to the short variable a without an explicit cast.
The first line, on the other hand, is permitted, as the compiler inserts an implicit cast in a so-called "compound assignment".
If a is a short, then a += b is equivalent to:
a = (short) (a + b);
However, when casting from int to short, the upper 16 bits are truncated. Information is therefore lost, as the following example
shows:
short a = 30_000;
int b = 50_000;
a += b;
System.out.println("a = " + a);
The program does not print 80000 (hexadecimal 0x13880), but 14464 (hexadecimal 0x3880).
To warn developers of this potentially undesirable behavior, a corresponding compiler warning was (finally!) added in Java 20.
Furthermore, the system property jdk.httpclient.keepalive.timeout.h2 has been added, with which you can overwrite this value
specifically for HTTP/2 connections.
However, when the default methods remove(Object key, Object value) and replace(K key, V oldValue, V newValue) were added to the
Map interface in Java 8, the JDK developers forgot to overwrite these methods in IdentityHashMap to use == instead of equals().
This error was corrected in Java 20, eight and a half years later. The fact that the bug was not noticed for so long is a sign that
IdentityHashMap is little used and may contain other bugs.
Intuitively, one would think that this HashMap offers space for 120 entries. However, this is not the case!
That is because the HashMap is initialized with a default load factor of 0.75. This means that, as soon as the HashMap is 75% full,
it gets rebuilt ("rehashed") with twice the size. This is to ensure that the elements are distributed as evenly as possible across the
HashMap’s buckets and that no bucket contains more than one element.
The HashMap initialized with a capacity of 120 can, therefore, only hold 120 × 0.75 = 90 entries.
To create a HashMap for 120 entries, you previously had to calculate the capacity by dividing the number of mappings by the
load factor: 120 ÷ 0.75 = 160. A HashMap for 120 entries, therefore, had to be created as follows:
Map<String, Integer> map = new HashMap<>(160);
Java 19 makes it easier for us – we can now write the following instead:
The newHashMap(...) method has also been implemented in LinkedHashMap and WeakHashMap. Take a look at the source code of
the new methods – you will see that they perform exactly the same calculation that we performed manually before.
Add java.time.InstantSource ⭐
The java.time.Clock class is extremely useful for writing tests public class Timer {
that check time-dependent functionality. If you inject Clock into private final InstantSource instantSource;
the application classes via dependency injection, for example, public Timer(InstantSource instantSource) {
you can mock it in tests and set a specific time for the test this.instantSource = instantSource;
using Clock.fixed(...), for example. }
However, as Clock provides the getZone() method, you always public Duration measure(Runnable runnable) {
have to think about the specific time zone with which you Instant start = instantSource.instant();
instantiate a Clock object. runnable.run();
To enable time zone-independent time sources, the Instant end = instantSource.instant();
java.time.InstantSource interface was extracted from Clock in return Duration.between(start, end);
Java 17. It only provides the instant() and millis() methods for }
querying the time, with millis() being implemented as a default }
method. @Test
The example at the top right shows a method that measures void shouldReturnDurationBetweenStartAndEnd() {
the execution time of a Runnable. In production, we can var instantSource = mock(InstantSource.class);
instantiate Timer with the system clock: when(instantSource.instant())
Timer timer = new Timer(Clock.systemDefaultZone()); .thenReturn(ofEpochMilli(1640033566000L))
.thenReturn(ofEpochMilli(1640033566075L));
We can test the method by mocking InstantSource, having the
Timer timer = new Timer(instantSource);
instant() method return two constant values and comparing the
Duration duration = timer.measure(() -> {});
return value of measure(...) with the difference between these
assertThat(duration).isEqualTo(ofMillis(75));
values (see test method on the right).
}
.
Switch Expressions – JEP 361 🌟
As of Java 14, switch statements can be written in the Example 1:
so-called arrow notation. One or more constants are switch (dayOfWeek) {
followed by an arrow and then a single instruction or case MONDAY, TUESDAY -> System.out.print("Beginning");
a code block. case WEDNESDAY, THURSDAY -> System.out.print("Middle");
The error-prone fallthrough to the next label case FRIDAY -> System.out.print("Almost!!!");
inherited from C no longer exists with this notation case SATURDAY, SUNDAY -> System.out.print("Weekend");
(see example 1). }
Switch can now also be used as an expression and Example 2:
return a value. With a switch expression, for public static int fibonacci(int i) {
example, we can write a recursive Fibonacci function return switch (i) {
quite elegantly (see example 2). case 0, 1 -> i;
Find more details about switch expressions at default -> fibonacci(i - 1) + fibonacci(i - 2);
www.happycoders.eu/java/switch-expressions/. };
}
Buffer.slice()
You can use the new Buffer.slice(int index, int length) method to create a view of a subsection of a buffer (e.g. ByteBuffer, IntBuffer,
DoubleBuffer) that starts at position index and contains length bytes.
FileSystems.newFileSystem()
You can use the FileSystems.newFileSystem(Path path, ClassLoader loader) method to create a pseudo file system whose content is
mapped to a file (such as a ZIP or JAR file).
The method was overloaded in Java 13 with a variant that makes it possible to pass a provider-specific configuration of the file
system via the env parameter: FileSystems.newFileSystem(Path path, Map env, ClassLoader loader).
Furthermore, two variants have been added, each without the loader parameter. A class loader is only required if the so-called
FileSystemProvider for the file type to be mapped is not registered in the JDK, but is to be loaded via the specified class loader.
This is not necessary for common file types such as ZIP or JAR.
.
New String and Files Methods 🌟
In Java 12, the following methods have been added to the String and Files classes:
● String.indent(int n) – indents the string on which indent(...) is called line by line by n spaces.
● String.transform(Function<...> f) – calls the function f with this string as a parameter and returns the result.
● Files.mismatch() – indicates the position of the first byte in which the files differ, or -1 for identical files.
Teeing Collector ⭐
The new "Teeing Collector" allows you to specify two stream collectors and a merge function that combines the results of the
collectors. The following example determines the difference between the maximum and minimum from the stream elements:
long width = numbersStream.collect(
Collectors.teeing(Collectors.minBy(Integer::compareTo), Collectors.maxBy(Integer::compareTo),
(min, max) -> (long) max.orElseThrow() - min.orElseThrow()));
Path.of() 🌟
As of Java 11, you can create a Path object using the static default method of(...) of the Path interface, e.g., like this:
Path.of("foo/bar/baz"); // ⟵ Relative path foo/bar/baz
Path.of("foo", "bar", "baz"); // ⟵ Relative path foo/bar/baz
Path.of("/", "foo", "bar", "baz"); // ⟵ Absolute path /foo/bar/baz
Immutable Collections 🌟
From Java 10 onwards, you can use List.copyOf(...), Set.copyOf(...), and Map.copyOf(...) to create immutable copies of lists, sets, and
maps. Attempting to modify collections created in this way results in an UnsupportedOperationException.
Similarly, you can use Collectors.toUnmodifiableList(), toUnmodifiableSet(), and toUnmodifiableMap() to collect streams in
immutable lists, sets, and maps.
Optional.orElseThrow() 🌟
The Optional.get() method throws a NoSuchElementException if an Optional is empty; it should therefore always be used in
combination with Optional.isPresent(). IDEs and static code analysis tools generate a warning if you dont’t do this. However, if
such an exception is desired, this warning is annoying.
This is why the method Optional.orElseThrow() was introduced, which does exactly the same as Optional.get(), but is not reported
by static code analysis tools, as its name clearly describes its behavior.