Last active
February 7, 2025 00:07
-
-
Save RajaniCode/06ac19e8a8524389a98dd8716bf9460c to your computer and use it in GitHub Desktop.
Java23.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Java 23 | |
// OpenJDK 23 | |
// $ wget https://download.java.net/java/GA/jdk23.0.2/6da2a6609d6e406f85c491fcb119101b/7/GPL/openjdk-23.0.2_linux-x64_bin.tar.gz | |
// $ sudo tar -xvzf openjdk-23.0.2_linux-x64_bin.tar.gz | |
// $ export PATH="$HOME/jdk-23.0.2/bin/":$PATH | |
// $ java --enable-preview --source 23 --enable-native-access=ALL-UNNAMED --add-modules=jdk.incubator.vector Java23.java && java Program | |
/* | |
# 1 # 455: Primitive Types in Patterns, instanceof, and switch (Preview) | |
# 2 # 466: Class-File API (Second Preview) | |
# 3 # 467: Markdown Documentation Comments | |
# 4 # 469: Vector API (Eighth Incubator) | |
# 5 # 473: Stream Gatherers (Second Preview) | |
# 6 # 471: Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal | |
# 7 # 474: ZGC: Generational Mode by Default | |
# 8 # 476: Module Import Declarations (Preview) | |
# 9 # 477: Implicitly Declared Classes and Instance Main Methods (Third Preview) | |
# 10 # 480: Structured Concurrency (Third Preview) | |
# 11 # 481: Scoped Values (Third Preview) | |
# 12 # 482: Flexible Constructor Bodies (Second Preview) | |
*/ | |
// # 8 # 476: Module Import Declarations (Preview) | |
// In this source file the simple name Element is ambiguous: | |
/* | |
import module java.desktop; // exports javax.swing.text, | |
// which has a public Element interface, | |
// and also exports javax.swing.text.html.parser, | |
// which has a public Element class | |
*/ | |
// # 8 # 476: Module Import Declarations (Preview) | |
// In this source file the simple name List is ambiguous: | |
/* | |
import module java.base; // exports java.util, which has a public List interface | |
import module java.desktop; // exports java.awt, which a public List class | |
*/ | |
// # 8 # 476: Module Import Declarations (Preview) | |
// Iin this source file the simple name Date is ambiguous: | |
/* | |
import module java.base; // exports java.util, which has a public Date class | |
import module java.sql; // exports java.sql, which has a public Date class | |
*/ | |
// # 8 # 476: Module Import Declarations (Preview) | |
// Resolving ambiguities is straightforward: Use a single-type-import declaration. For example, to resolve the ambiguous Date of the previous example: | |
import module java.base; // exports java.util, which has a public Date class | |
import module java.sql; // exports java.sql, which has a public Date class | |
import java.sql.Date; // resolve the ambiguity of the simple name Date! | |
/* | |
import java.io.IOException; | |
import java.lang.classfile.ClassFile; | |
import java.lang.constant.ClassDesc; | |
import java.lang.constant.MethodTypeDesc; | |
import java.lang.foreign.Arena; | |
import java.lang.foreign.MemorySegment; | |
import java.lang.foreign.ValueLayout; | |
import java.lang.invoke.VarHandle; | |
import java.lang.invoke.MethodHandles; | |
import java.lang.reflect.Field; | |
import java.nio.file.Path; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.concurrent.Callable; | |
import java.util.concurrent.ConcurrentLinkedQueue; | |
import java.util.concurrent.ExecutionException; | |
import java.util.concurrent.LinkedTransferQueue; | |
import java.util.concurrent.ThreadLocalRandom; | |
import java.util.concurrent.StructuredTaskScope; | |
import java.util.function.BiConsumer; | |
import java.util.function.BinaryOperator; | |
import java.util.function.Supplier; | |
import java.util.Queue; | |
import java.util.Random; | |
import java.util.List; | |
import java.util.stream.Gatherer; | |
import java.util.stream.Gatherers; | |
import java.util.stream.IntStream; | |
import java.util.stream.Stream; | |
import java.util.UUID; | |
*/ | |
import java.time.Duration; | |
import java.util.concurrent.StructuredTaskScope.Subtask; | |
import jdk.incubator.vector.FloatVector; | |
import jdk.incubator.vector.VectorSpecies; | |
// import sun.misc.Unsafe; | |
// # 9 # 477: Implicitly Declared Classes and Instance Main Methods (Third Preview) | |
// class Java23 { | |
// public static void main(String[] args) { | |
// # 3 # 467: Markdown Documentation Comments | |
/// Main method. | |
/// The main method is the entry point for the application and will subsequently invoke all the other methods required by the program. | |
void main() { | |
var propertiesSystem = new SystemProperties(); | |
propertiesSystem.print(); | |
System.out.println(); | |
// # 1 # 455: Primitive Types in Patterns, instanceof, and switch (Preview) | |
var previewPrimitiveTypesInPatternsInstanceofAndSwitch = new PrimitiveTypesInPatternsInstanceofAndSwitchPreview(); | |
previewPrimitiveTypesInPatternsInstanceofAndSwitch.print(); | |
System.out.println(); | |
// # 2 # 466: Class-File API (Second Preview) | |
var secondPreviewClassFileAPI = new ClassFileAPISecondPreview(); | |
secondPreviewClassFileAPI.print(); | |
System.out.println(); | |
// # 3 # 467: Markdown Documentation Comments | |
System.out.println("# 3 # 467: Markdown Documentation Comments"); | |
System.out.println("Note: Custom tags that could override future standard tags: @implSpec."); | |
System.out.println("To avoid potential overrides, use at least one period character (.) in custom tag names."); | |
System.out.println(); | |
// # 4 # 469: Vector API (Eighth Incubator) | |
var eighthIncubatorVectorAPI = new VectorAPIEighthIncubator(); | |
eighthIncubatorVectorAPI.print(); | |
System.out.println(); | |
// # 5 # 473: Stream Gatherers (Second Preview) | |
var secondPreviewStreamGatherers = new StreamGatherersSecondPreview(); | |
secondPreviewStreamGatherers.print(); | |
System.out.println(); | |
// # 6 # 471: Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal | |
var deprecateTheMemoryAccessMethodsInSunMiscUnsafe = new DeprecateTheMemoryAccessMethodsInSunMiscUnsafeForRemoval(); | |
deprecateTheMemoryAccessMethodsInSunMiscUnsafe.print(); | |
System.out.println(); | |
// # 7 # 474: ZGC: Generational Mode by Default | |
System.out.println("# 7 # 474: ZGC: Generational Mode by Default"); | |
System.out.print(""" | |
Make Generational ZGC the default mode of ZGC by changing the default value of the ZGenerational option from false to true. Deprecate the non-generational mode by deprecating the ZGenerational option. | |
"""); | |
System.out.println(); | |
// # 8 # 476: Module Import Declarations (Preview) | |
var previewModuleImportDeclarations = new ModuleImportDeclarationsPreview(); | |
previewModuleImportDeclarations.print(); | |
System.out.println(); | |
// # 9 # 477: Implicitly Declared Classes and Instance Main Methods (Third Preview) | |
System.out.print("# 9 # 477: Implicitly Declared Classes and Instance Main Methods (Third Preview)"); | |
print(""" | |
To simplify the writing of interactive small programs, we make three methods available for use in the body of every implicit class: | |
public static void println(Object obj); | |
public static void print(Object obj); | |
public static String readln(String prompt); | |
We achieve this effect by declaring a new top-level class in the java.io package named, simply, IO. | |
It declares the above three static methods for textual I/O with the console, and nothing else. | |
Every implicitly declared class automatically imports these static methods, as if the declaration | |
import static java.io.IO.*; | |
appears at the start of every source file containing an implicit class. | |
The new class java.io.IO is a preview API in JDK 23. | |
Every implicitly declared class can be considered to implicitly import the java.base module, as if the declaration | |
import module java.base; | |
appears at the start of every source file containing an implicit class. | |
"""); | |
System.out.println(); | |
// # 10 # 480: Structured Concurrency (Third Preview) | |
var thirdPreviewStructuredConcurrency = new StructuredConcurrencyThirdPreview(); | |
thirdPreviewStructuredConcurrency.print(); | |
System.out.println(); | |
// # 11 # 481: Scoped Values (Third Preview) | |
var thirdPreviewScopedValues = new ScopedValuesThirdPreview(); | |
thirdPreviewScopedValues.print(); | |
System.out.println(); | |
// # 12 # 482: Flexible Constructor Bodies (Second Preview) | |
var secondPreviewFlexibleConstructorBodies = new FlexibleConstructorBodiesSecondPreview(); | |
secondPreviewFlexibleConstructorBodies.print(); | |
} | |
// } | |
class Ticket { | |
public int getStatus() { | |
return new Random().nextInt(0, 4); | |
} | |
public int getYearlyFlights() { | |
return new Random().nextInt(-11, 11); | |
} | |
} | |
class PrimitiveTypesInPatternsInstanceofAndSwitchPreview { | |
private String issueDiscount() { | |
return "discount"; | |
} | |
private String issueGoldCard() { | |
return "gold card"; | |
} | |
private String appropriateAction() { | |
return "action"; | |
} | |
public void print() { | |
System.out.println("# 1 # 455: Primitive Types in Patterns, instanceof, and switch (Preview)"); | |
Ticket tick = new Ticket(); | |
var result = switch (tick.getStatus()) { | |
case 0 -> "okay"; | |
case 1 -> "warning"; | |
case 2 -> "error"; | |
default -> "unknown status: " + tick.getStatus(); | |
}; | |
System.out.println(result); | |
// Java 23 | |
// Pattern matching for switch to support primitive type patterns | |
// With support for primitive type patterns in switch, we could improve the switch expression by turning the default clause into a case clause with a primitive type pattern that exposes the matched value: | |
result = switch (tick.getStatus()) { | |
case 0 -> "okay"; | |
case 1 -> "warning"; | |
case 2 -> "error"; | |
// Java 22 // error: unexpected type | |
case int i -> "unknown status: " + i; | |
}; | |
System.out.println(result); | |
// Java 23 | |
// Supporting primitive type patterns would also allow guards to inspect the matched value: | |
result = switch (tick.getYearlyFlights()) { | |
case 0 -> "zero"; | |
case 1 -> "one"; | |
case 2 -> issueDiscount(); | |
case int i when i >= 10 -> issueGoldCard(); | |
case int i when i > 2 && i < 10 -> appropriateAction(); | |
case int i -> "cover all possible input values: " + i; | |
}; | |
System.out.println(result); | |
System.out.print(""" | |
The following table denotes the conversions that are permitted between primitive types. | |
Unconditionally exact conversions are denoted with the symbol ɛ. | |
The symbol ≈ means the identity conversion, ω means a widening primitive conversion, η means a narrowing primitive conversion, and ωη means a widening and narrowing primitive conversion. | |
The symbol — means no conversion is allowed. | |
o → byte short char int long float double boolean | |
From ↓ | |
byte ≈ ɛ ωη ɛ ɛ ɛ ɛ — | |
short η ≈ η ɛ ɛ ɛ ɛ — | |
char η η ≈ ɛ ɛ ɛ ɛ — | |
int η η η ≈ ɛ ω ɛ — | |
long η η η η ≈ ω ω — | |
float η η η η η ≈ ɛ — | |
double η η η η η η ≈ — | |
boolean — — — — — — — ≈ | |
"""); | |
byte b = 42; | |
System.out.println("byte b = 42 instanceof int: " + (b instanceof int)); // true (unconditionally exact) | |
int i = 42; | |
System.out.println("int int i = 42 instanceof byte: " + (i instanceof byte)); // true (exact) | |
i = 1000; | |
System.out.println("int i = 1000 instanceof byte: " + (i instanceof byte)); // false (not exact) | |
i = 16_777_217; // 2^24 + 1 | |
System.out.println("int i = 16_777_217 instanceof float: " + (i instanceof float)); // false (not exact) | |
System.out.println("int i = 16_777_217 instanceof double: " + (i instanceof double)); // true (unconditionally exact) | |
System.out.println("int i = 16_777_217 instanceof Integer: " + (i instanceof Integer)); // true (unconditionally exact) | |
System.out.println("int i = 16_777_217 instanceof Number: " + (i instanceof Number)); // true (unconditionally exact) | |
float f = 1000.0f; | |
System.out.println("float f = 1000.0f instanceof byte: " + (f instanceof byte)); // false | |
System.out.println("float f = 1000.0f instanceof int: " + (f instanceof int)); // true (exact) | |
System.out.println("float f = 1000.0f instanceof double: " + (f instanceof double)); // true (unconditionally exact) | |
double d = 1000.0d; | |
System.out.println("float f = 1000.0f instanceof byte: " + (d instanceof byte)); // false | |
System.out.println("float f = 1000.0f instanceof int: " + (d instanceof int)); // true (exact) | |
System.out.println("float f = 1000.0f instanceof float: " + (d instanceof float)); // true (exact) | |
Integer ii = 1000; | |
System.out.println("Integer ii = 1000 instanceof int: " + (ii instanceof int)); // true (exact) | |
System.out.println("Integer ii = 1000 instanceof float: " + (ii instanceof float)); // true (exact) | |
System.out.println("Integer ii = 1000 instanceof double: " + (ii instanceof double)); // true (exact) | |
ii = 16_777_217; | |
System.out.println("int ii = 16_777_217 instanceof float: " + (ii instanceof float)); // false (not exact) | |
System.out.println("int ii = 16_777_217 instanceof double: " + (ii instanceof double)); // true (exact) | |
Byte byt = Byte.MAX_VALUE; | |
var exhaustive = switch (byt) { // exhaustive switch | |
case int p -> 0; | |
}; | |
System.out.println("Exhaustive switch: " + exhaustive); | |
float flt = Float.MAX_VALUE; | |
var expanded =switch (flt) { | |
case 0f -> 5f; | |
case 1.0f -> 6f; | |
// case 0.999999999f -> 7f; // error: duplicate label | |
case float e when e == 1f -> 6f + e; | |
case float e -> 7f + e; | |
}; | |
System.out.println("Expanded primitive support in switch: " + expanded); | |
boolean bool = true ^ false; | |
var exhaust = switch (bool) { | |
case true -> "Truthy"; | |
case false -> "Falsy"; | |
// Alternatively: case true, false -> "Truthy/Falsy"; | |
// default -> "Default"; // illegal if there were a default clause // error: switch has both boolean values and a default label | |
}; | |
System.out.println("Exhaustive boolean switch: " + exhaust); | |
} | |
} | |
class ClassFileAPISecondPreview { | |
public void print() { | |
System.out.println("# 2 # 466: Class-File API (Second Preview)"); | |
String javaVersion = String.format("Java Version: %s", System.getProperty("java.version")); | |
// % java Program | |
try { | |
ClassFile.of().buildTo(Path.of("Program.class"), ClassDesc.of("Program"), classBuilder -> classBuilder | |
.withMethodBody("main", MethodTypeDesc.ofDescriptor("([Ljava/lang/String;)V"), ClassFile.ACC_PUBLIC + ClassFile.ACC_STATIC, | |
codeBuilder -> codeBuilder | |
.getstatic(ClassDesc.of("java.lang.System"), "out", ClassDesc.of("java.io.PrintStream")) | |
.ldc(javaVersion) | |
.invokevirtual(ClassDesc.of("java.io.PrintStream"), "println", MethodTypeDesc.ofDescriptor("(Ljava/lang/Object;)V")) | |
.return_())); | |
} catch (IOException ex) { | |
// ex.printStackTrace(); | |
System.out.println(ex.getMessage()); | |
} | |
} | |
} | |
// # 3 # 467: Markdown Documentation Comments | |
/// The {@code MarkdownDocumentationComments} class implements an application that prints Java 23 features to standard output. | |
public class MarkdownDocumentationComments { | |
// # 3 # 467: Markdown Documentation Comments | |
/// Private constructor. | |
/// This constructor is not used and prevents the default constructor being generated. | |
private MarkdownDocumentationComments() { } | |
// # 3 # 467: Markdown Documentation Comments | |
/// Returns a hash code value for the object. This method is | |
/// supported for the benefit of hash tables such as those provided by | |
/// [java.util.HashMap]. | |
/// | |
/// The general contract of `hashCode` is: | |
/// | |
/// - Whenever it is invoked on the same object more than once during | |
/// an execution of a Java application, the `hashCode` method | |
/// must consistently return the same integer, provided no information | |
/// used in `equals` comparisons on the object is modified. | |
/// This integer need not remain consistent from one execution of an | |
/// application to another execution of the same application. | |
/// - If two objects are equal according to the | |
/// [equals][#equals(Object)] method, then calling the | |
/// `hashCode` method on each of the two objects must produce the | |
/// same integer result. | |
/// - It is _not_ required that if two objects are unequal | |
/// according to the [equals][#equals(Object)] method, then | |
/// calling the `hashCode` method on each of the two objects | |
/// must produce distinct integer results. However, the programmer | |
/// should be aware that producing distinct integer results for | |
/// unequal objects may improve the performance of hash tables. | |
/// | |
/// @impl.Spec | |
/// As far as is reasonably practical, the `hashCode` method defined | |
/// by class `Object` returns distinct integers for distinct objects. | |
/// | |
/// @return a hash code value for this object. | |
/// @see java.lang.Object#equals(java.lang.Object) | |
/// @see java.lang.System#identityHashCode | |
public native int hashCode(); | |
// # 3 # 467: Markdown Documentation Comments | |
// Java 23 GitHub Flavored Markdown // Sample // Inline Code Snippet | |
/// Code snippet for {@code isTrue}: | |
/// {@snippet : | |
/// if (isTrue) { | |
/// text = java.util.stream.Stream.of(text) | |
/// .map(string -> new StringBuilder(string).reverse()) | |
/// .collect(java.util.stream.Collectors.joining()); | |
/// }} | |
/// | |
/// Sample | |
/// ------ | |
/// | |
/// | Text | IsReverse | Reverse | | |
/// |-------|-----------|---------| | |
/// | Alpha | true | ahplA | | |
/// | Alpha | false | Alpha | | |
/// | |
/// @param text the input of type String. | |
/// @param isReverse flag of type boolean. | |
public void codeSnippetInline(String text, boolean isReverse) { | |
if (isReverse) { | |
text = java.util.stream.Stream.of(text) | |
.map(string -> new StringBuilder(string).reverse()) | |
.collect(java.util.stream.Collectors.joining()); | |
} | |
System.out.println(text); | |
} | |
} | |
class VectorAPIEighthIncubator { | |
// Simple scalar computation over elements of arrays | |
// Assume that the array arguments are of the same length | |
private void scalarComputation(float[] a, float[] b, float[] c) { | |
for (int i = 0; i < a.length; i++) { | |
c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f; | |
} | |
System.out.println(Arrays.toString(c)); | |
} | |
// Equivalent vector computation, using the Vector API | |
private static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED; | |
private void vectorComputation(float[] a, float[] b, float[] c) { | |
int i = 0; | |
int upperBound = SPECIES.loopBound(a.length); | |
for (; i < upperBound; i += SPECIES.length()) { | |
// FloatVector va, vb, vc; | |
var va = FloatVector.fromArray(SPECIES, a, i); | |
var vb = FloatVector.fromArray(SPECIES, b, i); | |
var vc = va.mul(va) | |
.add(vb.mul(vb)) | |
.neg(); | |
vc.intoArray(c, i); | |
} | |
for (; i < a.length; i++) { | |
c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f; | |
} | |
System.out.println(Arrays.toString(c)); | |
} | |
// On platforms supporting predicate registers, the above could be written more simply, without the scalar loop to process the tail elements, while still achieving optimal performance | |
private void vectorComputationPredicateRegisters(float[] a, float[] b, float[] c) { | |
for (int i = 0; i < a.length; i += SPECIES.length()) { | |
// VectorMask<Float> m; | |
var m = SPECIES.indexInRange(i, a.length); | |
// FloatVector va, vb, vc; | |
var va = FloatVector.fromArray(SPECIES, a, i, m); | |
var vb = FloatVector.fromArray(SPECIES, b, i, m); | |
var vc = va.mul(va) | |
.add(vb.mul(vb)) | |
.neg(); | |
vc.intoArray(c, i, m); | |
} | |
System.out.println(Arrays.toString(c)); | |
} | |
public void print() { | |
System.out.println("# 4 # 469: Vector API (Eighth Incubator)"); | |
float[] alpha = { 1.2f, 2.3f }; | |
float[] beta = { 3.4f, 5.6f }; | |
float[] gamma = { 7.8f, 9.1f }; | |
System.out.println("Support the ARM Scalar Vector Extension (SVE) platform."); | |
System.out.println("Scalar Computation"); | |
scalarComputation(alpha, beta, gamma); | |
System.out.println("Vector Computation"); | |
vectorComputation(alpha, beta, gamma); | |
System.out.println("An API to express vector computations that reliably compile at runtime to optimal vector instructions on supported CPU architectures, thus achieving performance superior to equivalent scalar computations."); | |
vectorComputationPredicateRegisters(alpha, beta, gamma); | |
} | |
} | |
record BiggestInt(int limit) implements Gatherer<Integer, List<Integer>, Integer> { | |
// The Initializer Function creates a new private ArrayList to keep track of the largest integer across elements. | |
// The optional initializer function creates the gatherer's private state object. | |
// This creates an empty ArrayList with a capacity of only one Integer as its meant to store the largest Integer the gatherer has encountered so far. | |
@Override | |
public Supplier<List<Integer>> initializer() { | |
return () -> new ArrayList<Integer>(1); | |
} | |
// The Integrator Function | |
// Every gatherer requires an integrator function. | |
// To create an integrator function, call either Gatherer.Integrator.of(Gatherer.Integrator) or Gatherer.Integrator.ofGreedy(Gatherer.Integrator). | |
// These methods take as an argument a lambda expression that contains three parameters. | |
// This uses the following lambda expression: | |
@Override | |
public Integrator<List<Integer>, Integer, Integer> integrator() { | |
return Integrator.of( | |
(max, element, downstream) -> { | |
// Save the integer if it's the largest so far. | |
if (max.isEmpty()) { | |
max.addFirst(element); | |
} | |
else if (element > max.getFirst()) { | |
max.set(0, element); | |
} | |
// If the integer is equal or greater to the limit, "short-circuit": emit the current integer downstream, and return false to stop processing stream elements | |
if (element >= limit) { | |
downstream.push(element); | |
return false; | |
} | |
// Return true to continue processing stream elements | |
return true; | |
} | |
); | |
} | |
// The Combiner Function, which is used during parallel evaluation | |
// The optional combiner function is called only if you're running the gatherer in parallel. | |
// The combiner function is a lambda expression that contains two parameters, which represent two private state objects. | |
// This returns the private state object (an ArrayList) that contains the largest integer. | |
@Override | |
public BinaryOperator<List<Integer>> combiner() { | |
return (leftMax, rightMax) -> { | |
// If either the "left" or "right" ArrayLists contain no value, then return the other | |
if (leftMax.isEmpty()) { | |
return rightMax; | |
} | |
if (rightMax.isEmpty()) { | |
return leftMax; | |
} | |
// Return the ArrayList that contains the larger integer | |
int leftVal = leftMax.getFirst(); | |
int rightVal = rightMax.getFirst(); | |
if (leftVal > rightVal) { | |
return leftMax; | |
} | |
else { | |
return rightMax; | |
} | |
}; | |
} | |
// The Finisher Function | |
// The optional finisher function is a lambda expression that contains two parameters: | |
// The parameter max is the private state object and downstream is a Gatherer.Downstream object. | |
// In this, the finisher function pushes the value contained in the private state object. | |
// Note that this value won't be pushed if the integrator function returned false. | |
// You can check whether a Downstream object is no longer processing input elements by calling the method Gatherer.Downstream::isRejecting. | |
// If it returns true, it's no longer processing input elements. | |
// Note: If the finisher function pushes a value downstream, then that value is contained in an Optional object. | |
@Override | |
public BiConsumer<List<Integer>, Downstream<? super Integer>> finisher() { | |
// Emit the largest integer, if there is one, downstream | |
return (max, downstream) -> { | |
if (!max.isEmpty()) { | |
downstream.push(max.getFirst()); | |
} | |
}; | |
} | |
} | |
class StreamGatherersSecondPreview { | |
// Creating Gatherers with Factory Methods | |
// Instead of implementing the Gatherer interface, you can call one of the factory methods in the Gatherer interface to create a gatherer. | |
// The following is the same one as described in Creating a Gatherer except it calls the Gatherer::of method: | |
public Gatherer<Integer, List<Integer>, Integer> biggestInt(int limit) { | |
return Gatherer.of( | |
// Supplier | |
() -> { return new ArrayList<Integer>(1); }, | |
// Integrator | |
Gatherer.Integrator.of( | |
(max, element, downstream) -> { | |
System.out.println("Processing " + element); | |
if (max.isEmpty()) max.addFirst(element); | |
else if (element > max.getFirst()) max.set(0, element); | |
if (element >= limit) { | |
downstream.push(element); | |
return false; | |
} | |
return true; | |
} | |
), | |
// Combiner | |
(leftMax, rightMax) -> { | |
if (leftMax.isEmpty()) return rightMax; | |
if (rightMax.isEmpty()) return leftMax; | |
int leftVal = leftMax.getFirst(); | |
int rightVal = rightMax.getFirst(); | |
if (leftVal > rightVal) return leftMax; | |
else return rightMax; | |
}, | |
// Finisher | |
(max, downstream) -> { | |
if (!max.isEmpty()) { | |
downstream.push(max.getFirst()); | |
} | |
} | |
); | |
} | |
public void print() { | |
System.out.println("# 5 # 473: Stream Gatherers (Second Preview)"); | |
System.out.println("Record: new BiggestInt(555): " + new BiggestInt(555)); | |
System.out.println("Gatherer (400, 300, 200, 777, 600, 800, 1000) gather(new BiggestInt(555) leftMax vs. rightMax findFirst"); | |
System.out.println(Stream.of(400, 300, 200, 777, 600, 800, 1000) | |
.gather(new BiggestInt(555)) | |
.findFirst() | |
.get()); | |
System.out.println("Gatherer (400, 300, 200, 777, 600, 800, 1000) gather(new BiggestInt(555) parallel leftMax vs. rightMax findFirst"); | |
System.out.println(Stream.of(400, 300, 200, 777, 600, 800, 1000) | |
.gather(new BiggestInt(555)) | |
.parallel() | |
.findFirst() | |
.get()); | |
System.out.println("Gatherers with Factory Methods (400, 300, 200, 777, 600, 800, 1000) gather(biggestInt(555)) leftMax vs. rightMax parallel"); | |
System.out.println(Stream.of(400, 300, 200, 777, 600, 800, 1000) | |
.gather(biggestInt(555)) | |
.parallel() | |
.findFirst() | |
.get()); | |
System.out.println("Built-In Gatherers"); | |
// Built-In Gatherers | |
// The Gatherers class contains the following built-in gatherers: | |
// fold(Supplier initial, BiFunction folder): | |
System.out.println("Gatherers.fold .forEach(): (2, 4, 6, 8): 6, (x, y) -> x * y)"); | |
Stream.of(2, 4, 6, 8) | |
.gather(Gatherers.fold(() -> 6, (x, y) -> x * y)) | |
.forEach(System.out::println); | |
// This is an many-to-one gatherer that constructs an aggregate incrementally until no more input elements exist. | |
// It has two parameters: | |
// initial: This is the identity value or the value that the gatherer emits if the input stream contains no elements. | |
// folder: This is a lambda expression that contains two parameters: the first is the aggregate the gatherer is constructing and the second is the element that's currently being processed. | |
// The following uses the fold gatherer to convert a stream of numbers to a semicolon-separated string: | |
System.out.println("Gatherers.fold .findFirst().get(): (2, 4, 6, 8): Comma Space Separated"); | |
var commaSpaceSeparated = Stream.of(2, 4, 6, 8) | |
.gather( | |
Gatherers.fold( | |
() -> "", | |
(y, x) -> { | |
if (y.equals("")) { | |
return x.toString(); | |
} | |
return y + ", " + x; | |
} | |
) | |
) | |
.findFirst() | |
.get(); | |
System.out.println(commaSpaceSeparated); | |
// mapConcurrent(int maxConcurrency, Function mapper): | |
int maxConcurrency = 10; | |
System.out.println("Gatherers.mapConcurrent .forEach(): (2, 4, 6, 8): maxConcurrency, x -> x * 2"); | |
Stream.of(2, 4, 6, 8) | |
.gather(Gatherers.mapConcurrent(maxConcurrency, x -> x * 2)) | |
.forEach(System.out::println); | |
// This is a one-to-one gatherer that invokes mapper for each input element in the stream concurrently, up to the limit specified by maxConcurrency. | |
// You can use this limit for the following: | |
// As a rate-limiting construct to prevent the gatherer from issuing too many concurrent requests to things like an external service or a database | |
// As a performance-enhancer to enable multiple, separate operations to be performed concurrently while avoiding converting the entire stream into a parallel stream | |
// This gatherer preserves the ordering of the stream. | |
System.out.println("Gatherers.mapConcurrent .findFirst().get(): (2, 4, 6, 8): maxConcurrency, x -> x * 2"); | |
var mapConcurrentFindFirstGet = Stream.of(2, 4, 6, 8) | |
.gather(Gatherers.mapConcurrent(maxConcurrency, x -> x * 2)) | |
.findFirst() | |
.get(); | |
System.out.println(mapConcurrentFindFirstGet); | |
// scan(Supplier initial, BiFunction scanner): | |
// This is a one-to-one gatherer that performs a prefix scan, which is an incremental accumulation. | |
// Starting with an initial value obtained from the parameter initial, it obtains subsequent values by applying scanner to the current value and the next input element. | |
// The gatherer then emits the value downstream. | |
System.out.println("Gatherers.scan .forEach(): (2, 4, 6, 8): 6, (x, y) -> x * y"); | |
Stream.of(2, 4, 6, 8) | |
.gather(Gatherers.scan(() -> 6, (x, y) -> x * y)) | |
.forEach(System.out::println); | |
// windowFixed(int windowSize): | |
// This is a many-to-many gatherer that gathers elements in windows, which are encounter-ordered groups of elements. | |
// The parameter windowSize specifies the size of the windows. | |
System.out.println("Gatherers.windowFixed: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10): windowFixed(3)"); | |
List<List<Integer>> windows = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).gather(Gatherers.windowFixed(3)).toList(); | |
windows.forEach(System.out::println); | |
// windowSliding(int windowSize): | |
// Similar to windowFixed, this is a many-to-many gatherer that gathers elements in windows. | |
// However, each subsequent window includes all elements of the previous window except for its first element, and adds the next element in the stream. | |
System.out.println("Gatherers.windowSliding: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10): windowSliding(3)"); | |
List<List<Integer>> moreWindows = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).gather(Gatherers.windowSliding(3)).toList(); | |
moreWindows.forEach(System.out::println); | |
// Composing Gatherers | |
// You can compose two or more gatherers into a single gatherer with the Gatherer.andThen(Gatherer). | |
System.out.println("Composing Gatherers with Gatherer.andThen(Gatherer): scan.andThen(fold): (1, 2, 3, 4, 5, 6, 7, 8, 9, 10): 100, (x, y) -> x + y)"); | |
Gatherer<Integer, ?, Integer> scan = Gatherers.scan(() -> 100, (x, y) -> x + y); | |
Gatherer<Integer, ?, String> fold = | |
Gatherers.fold(() -> "", | |
(y, x) -> { | |
if (y.equals("")) { | |
return x.toString(); | |
} | |
return y + "; " + x; | |
}); | |
var t = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) | |
.gather(scan.andThen(fold)) | |
.findFirst() | |
.get(); | |
System.out.println(t); | |
} | |
} | |
// On-heap memory access | |
/* | |
// Suppose class OnHeap has an int field that we wish to double atomically. | |
// We can do that using sun.misc.Unsafe: | |
class OnHeap { | |
private static final Unsafe UNSAFE; // A sun.misc.Unsafe object | |
private static final long X_OFFSET; | |
static { | |
try { | |
Field f = Unsafe.class.getDeclaredField("theUnsafe"); | |
f.setAccessible(true); | |
UNSAFE = (Unsafe) f.get(null); | |
X_OFFSET = UNSAFE.objectFieldOffset(OnHeap.class.getDeclaredField("x")); | |
} catch (Exception ex) { throw new AssertionError(ex); } | |
} | |
private int x; | |
public boolean tryToDoubleAtomically() { | |
int oldValue = x; | |
return UNSAFE.compareAndSwapInt(this, X_OFFSET, oldValue, oldValue * 2); | |
} | |
} | |
*/ | |
// We can improve that to use the standard VarHandle API: | |
class OnHeap { | |
private static final VarHandle X_VH; | |
static { | |
try { | |
X_VH = MethodHandles.lookup().findVarHandle(OnHeap.class, "x", int.class); | |
} catch (Exception ex) { throw new AssertionError(ex); } | |
} | |
private int x; | |
public boolean tryToDoubleAtomically() { | |
int oldValue = x; | |
return X_VH.compareAndSet(this, oldValue, oldValue * 2); | |
} | |
} | |
/* | |
// We can use sun.misc.Unsafe to perform a volatile write of an array element: | |
class OnHeapVolatile { | |
private static final Unsafe UNSAFE; | |
private static final int ARRAY_BASE; | |
private static final int ARRAY_SCALE; | |
static { | |
try { | |
Field f = Unsafe.class.getDeclaredField("theUnsafe"); | |
f.setAccessible(true); | |
UNSAFE = (Unsafe) f.get(null); | |
ARRAY_BASE = UNSAFE.arrayBaseOffset(int[].class); | |
ARRAY_SCALE = UNSAFE.arrayIndexScale(int[].class); | |
} catch (Exception ex) { throw new AssertionError(ex); } | |
} | |
public int[] NumberArray = new int[10]; | |
public void setVolatile(int index, int value) { | |
if (index < 0 || index >= NumberArray.length) | |
throw new ArrayIndexOutOfBoundsException(index); | |
UNSAFE.putIntVolatile(NumberArray, ARRAY_BASE + ARRAY_SCALE * index, value); | |
} | |
} | |
*/ | |
// We can improve that to use VarHandle: | |
class OnHeapVolatile { | |
private static final VarHandle AVH = MethodHandles.arrayElementVarHandle(int[].class); | |
public int[] NumberArray = new int[10]; | |
public void setVolatile(int index, int value) { | |
AVH.setVolatile(NumberArray, index, value); | |
} | |
} | |
// Off-heap memory access | |
/* | |
// Here is a class that uses sun.misc.Unsafe to allocate an off-heap buffer and perform three operations: a volatile write of an int, a bulk initialization of a subset of the buffer, and a copy of the buffer data into a Java int array: | |
class OffHeapIntBuffer { | |
private static final Unsafe UNSAFE; | |
private static final int ARRAY_BASE; | |
private static final int ARRAY_SCALE; | |
static { | |
try { | |
Field f = Unsafe.class.getDeclaredField("theUnsafe"); | |
f.setAccessible(true); | |
UNSAFE = (Unsafe) f.get(null); | |
ARRAY_BASE = UNSAFE.arrayBaseOffset(int[].class); | |
ARRAY_SCALE = UNSAFE.arrayIndexScale(int[].class); | |
} catch (Exception ex) { throw new AssertionError(ex); } | |
} | |
private final long size; | |
private long bufferPtr; | |
public OffHeapIntBuffer(long size) { | |
this.size = size; | |
this.bufferPtr = UNSAFE.allocateMemory(size * ARRAY_SCALE); | |
} | |
public void deallocate() { | |
if (bufferPtr == 0) return; | |
UNSAFE.freeMemory(bufferPtr); | |
bufferPtr = 0; | |
} | |
private boolean checkBounds(long index) { | |
if (index < 0 || index >= size) | |
throw new IndexOutOfBoundsException(index); | |
return true; | |
} | |
public void setVolatile(long index, int value) { | |
checkBounds(index); | |
UNSAFE.putIntVolatile(null, bufferPtr + ARRAY_SCALE * index, value); | |
} | |
public void initialize(long start, long n) { | |
checkBounds(start); | |
checkBounds(start + n-1); | |
// https://openjdk.org/jeps/471 // Erratum | |
// error: no suitable method found for setMemory(long,long,int) | |
// UNSAFE.setMemory(bufferPtr + start * ARRAY_SCALE, n * ARRAY_SCALE, 0); | |
byte b = 0; | |
UNSAFE.setMemory(bufferPtr + start * ARRAY_SCALE, n * ARRAY_SCALE, b); | |
} | |
public int[] copyToNewArray(long start, int n) { | |
checkBounds(start); | |
checkBounds(start + n-1); | |
int[] a = new int[n]; | |
UNSAFE.copyMemory(null, bufferPtr + start * ARRAY_SCALE, a, ARRAY_BASE, n * ARRAY_SCALE); | |
return a; | |
} | |
} | |
*/ | |
// We can improve that to use the standard Arena and MemorySegment APIs: | |
class OffHeapIntBuffer { | |
private static final VarHandle ELEM_VH = ValueLayout.JAVA_INT.arrayElementVarHandle(); | |
private final Arena arena; | |
private final MemorySegment buffer; | |
public OffHeapIntBuffer(long size) { | |
this.arena = Arena.ofShared(); | |
this.buffer = arena.allocate(ValueLayout.JAVA_INT, size); | |
} | |
public void deallocate() { | |
arena.close(); | |
} | |
public void setVolatile(long index, int value) { | |
ELEM_VH.setVolatile(buffer, 0L, index, value); | |
} | |
public void initialize(long start, long n) { | |
buffer.asSlice(ValueLayout.JAVA_INT.byteSize() * start, | |
ValueLayout.JAVA_INT.byteSize() * n) | |
.fill((byte) 0); | |
} | |
public int[] copyToNewArray(long start, int n) { | |
return buffer.asSlice(ValueLayout.JAVA_INT.byteSize() * start, | |
ValueLayout.JAVA_INT.byteSize() * n) | |
.toArray(ValueLayout.JAVA_INT); | |
} | |
} | |
class DeprecateTheMemoryAccessMethodsInSunMiscUnsafeForRemoval { | |
public void print() { | |
System.out.println("# 6 # 471: Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal"); | |
System.out.print(""" | |
Deprecate the memory-access methods in sun.misc.Unsafe for removal in a future release. These unsupported methods have been superseded by standard APIs, namely the VarHandle API (JEP 193, JDK 9) and the Foreign Function & Memory API (JEP 454, JDK 22). We strongly encourage library developers to migrate from sun.misc.Unsafe to supported replacements, so that applications can migrate smoothly to modern JDK releases. | |
"""); | |
var heapOn = new OnHeap(); | |
System.out.println("On-heap memory access: " + heapOn.tryToDoubleAtomically()); | |
var volatileOnHeap = new OnHeapVolatile(); | |
volatileOnHeap.setVolatile(5, 4); | |
System.out.println("On-heap memory access volatile: " + Arrays.toString(volatileOnHeap.NumberArray)); | |
var intBufferOffHeap = new OffHeapIntBuffer(10L); | |
System.out.println("Off-heap memory access: " + Arrays.toString(intBufferOffHeap.copyToNewArray(4L, 2))); | |
} | |
} | |
class ModuleImportDeclarationsPreview { | |
public void print() { | |
System.out.println("# 8 # 476: Module Import Declarations (Preview)"); | |
System.out.print(""" | |
A module import declaration has the form | |
import module M; | |
It imports, on demand, all of the public top-level classes and interfaces in | |
The packages exported by the module M to the current module, and | |
The packages exported by the modules that are read by the current module due to reading the module M. | |
The second clause allows a program to use the API of a module, which might refer to classes and interfaces from other modules, without having to import all of those other modules. | |
"""); | |
} | |
} | |
// Common Shutdown Policies: ShutdownOnSuccess and ShutdownOnFailure | |
// The StructuredTaskScope class contains two subclasses, ShutdownOnFailure and ShutdownOnSuccess. | |
// These subclasses implement two common shutdown policies. | |
// ShutdownOnFailure cancels all subtasks if one of them fails, while ShutdownOnSuccess cancels all remaining subtasks if one of them succeeds. | |
// These shutdown policies are of short-circuiting patterns. | |
// A short-circuiting pattern encourages subtasks to complete quickly by enabling the main task to interrupt and cancel subtasks whose outcomes are no longer needed. | |
// The following is the StructuredTaskScope.ShutdownOnFailure and StructuredTaskScope.ShutdownOnSuccess classes. | |
// Each task scope forks five subtasks that sleep for a random duration of time. However, if the duration is greater than a specified threshold, the subtask throws a TooSlowException. | |
// The handleShutDownOnFailure() method prints the total duration of all subtasks if none of them threw an exception. | |
// The handleShutDownOnSuccess() method prints the duration of the subtask that is completed first. | |
class ShortCircuitingPattern { | |
class TooSlowException extends Exception { | |
public TooSlowException(String s) { | |
super(s); | |
} | |
} | |
public Integer randomTask(int maxDuration, int threshold) throws InterruptedException, TooSlowException { | |
int t = new Random().nextInt(maxDuration); | |
System.out.println("Duration: " + t); | |
if (t > threshold) { | |
throw new TooSlowException("Duration " + t + " greater than threshold " + threshold); | |
} | |
Thread.sleep(t); | |
return Integer.valueOf(t); | |
} | |
// StructuredTaskScope.ShutdownOnFailure class captures the first exception thrown by one of its subtasks, then invokes the shutdown method. | |
// This prevents any new subtasks from starting, interrupts all unfinished threads running other subtasks, and enables the application to continue running. | |
// To access the captured exception, call the ShutdownOnFailure::exception method. | |
// If you want to rethrow the exception instead, call the ShutdownOnFailure::throwIfFailed method, which this/ | |
private void handleShutdownOnFailure() throws ExecutionException, InterruptedException { | |
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { | |
List<Subtask<Integer>> subtasks = IntStream.range(0, 5) | |
.mapToObj(i -> scope.fork(() -> randomTask(1000, 850))) | |
.toList(); | |
scope.join() | |
.throwIfFailed(); | |
var totalDuration = subtasks.stream() | |
.map(t -> t.get()) | |
.reduce(0, Integer::sum); | |
System.out.println("Total duration: " + totalDuration); | |
} | |
} | |
// StructuredTaskScope.ShutdownOnSuccess<T> class captures the result of the first subtask to be completed successfully, and like ShutdownOnFailure, invokes the shutdown method. | |
// To access the result of the subtask that completed successfully, call the ShutdownOnSuccess::result method, which this example demonstrates. | |
private void handleShutdownOnSuccess() throws ExecutionException, InterruptedException { | |
// try (var scope = new StructuredTaskScope.ShutdownOnSuccess<Integer>()) { | |
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<>()) { | |
List<Subtask<Integer>> subtasks = | |
IntStream.range(0, 5) | |
.mapToObj(i -> scope.fork(() -> randomTask(1000, 850))) | |
.toList(); | |
scope.join(); | |
System.out.println("First task to finish: " + scope.result()); | |
} | |
} | |
// Print the total duration of the subtasks that completed successfully and the exceptions of the subtasks that threw exceptions using ScopeZ<T> | |
// In the ScopeZ<T> class, before successfulTasks() and failedTasks() return streams for successSubtasks and failedSubtasks, respectively, it calls StructuredTaskScope::ensureOwnerAndJoined. | |
// This ensures that the example can only access successSubtasks and failedSubtasks provided that the current thread is the owner of the task scope, and the task scope has joined the subtasks after they have been forked. | |
private void handleSuccessfulAndFailedTasks() throws InterruptedException { | |
try (var scope = new ScopeZ<>()) { | |
var subtasks = IntStream.range(0, 5) | |
.mapToObj(i -> scope.fork(() -> randomTask(1000, 500))) | |
.toList(); | |
scope.join(); | |
var totalDuration = scope.successfulTasks() | |
.mapToInt(st -> (Integer)((Subtask)st).get()) | |
.reduce(0, Integer::sum); | |
System.out.println("Total duration: " + totalDuration); | |
scope.failedTasks() | |
.forEach(ft -> | |
System.out.println(((Exception)((Subtask)ft).exception()).getMessage())); | |
} | |
} | |
public void randomTasks() { | |
try { | |
System.out.println("Running handle ShutdownOnFailure..."); | |
handleShutdownOnFailure(); | |
} catch (Exception e) { | |
System.out.println(e.getMessage()); | |
} | |
try { | |
System.out.println("Running handle ShutdownOnSuccess<T>..."); | |
handleShutdownOnSuccess(); | |
} catch (Exception e) { | |
System.out.println(e.getMessage()); | |
} | |
try { | |
System.out.println("Running handle Successful And Failed Tasks..."); | |
handleSuccessfulAndFailedTasks(); | |
} catch (Exception e) { | |
System.out.println(e.getMessage()); | |
} | |
} | |
} | |
// Java 21 Preview | |
class ScopeX<T> extends StructuredTaskScope<T> { | |
private final Queue<T> results = new ConcurrentLinkedQueue<>(); | |
ScopeX() { super(null, Thread.ofVirtual().factory()); } | |
// Java 21 Preview | |
@Override | |
protected void handleComplete(Subtask<? extends T> subtask) { | |
if (subtask.state() == Subtask.State.SUCCESS) { | |
results.add(subtask.get()); | |
} | |
} | |
// Java 21 Preview | |
@Override | |
public ScopeX<T> join() throws InterruptedException { | |
super.join(); | |
return this; | |
} | |
// Java 21 Preview | |
// Returns a stream of results from the subtasks that completed successfully | |
public Stream<T> results() { | |
super.ensureOwnerAndJoined(); | |
return results.stream(); | |
} | |
} | |
class ScopeY<T> extends StructuredTaskScope<T> { | |
private final Queue<Subtask<? extends T>> subtasks = new LinkedTransferQueue<>(); | |
@Override | |
protected void handleComplete(Subtask<? extends T> subtask) { | |
if (subtask.state() == Subtask.State.SUCCESS) { | |
subtasks.add(subtask); | |
} | |
} | |
@Override | |
public ScopeY<T> join() throws InterruptedException { | |
super.join(); | |
return this; | |
} | |
public Stream<Subtask<? extends T>> completedSuccessfully() { | |
super.ensureOwnerAndJoined(); | |
return subtasks.stream(); | |
} | |
} | |
class ScopeZ<T> extends StructuredTaskScope<T> { | |
private final Queue<Subtask<? extends T>> successSubtasks = new LinkedTransferQueue<>(); | |
private final Queue<Subtask<? extends T>> failedSubtasks = new LinkedTransferQueue<>(); | |
@Override | |
protected void handleComplete(Subtask<? extends T> subtask) { | |
if (subtask.state() == Subtask.State.SUCCESS) { | |
successSubtasks.add(subtask); | |
} else if (subtask.state() == Subtask.State.FAILED) { | |
failedSubtasks.add(subtask); | |
} | |
} | |
@Override | |
public ScopeZ<T> join() throws InterruptedException { | |
super.join(); | |
return this; | |
} | |
public Stream<Subtask<? extends T>> successfulTasks() { | |
super.ensureOwnerAndJoined(); | |
return successSubtasks.stream(); | |
} | |
public Stream<Subtask<? extends T>> failedTasks() { | |
super.ensureOwnerAndJoined(); | |
return failedSubtasks.stream(); | |
} | |
} | |
// Debugging StructuredTaskScope and Its Forked Subtasks with the jcmd Command | |
// The jcmd tool can emit a thread dump in JSON format. | |
// This thread dump displays the threads running the forked subtasks of a StructuredTaskScope in an array, along with their stack traces. | |
// The following that forks three subtasks. | |
// These subtasks repeatedly alternate between printing a message and sleeping for one second. | |
class ShortCircuitingPatternObservable { | |
private Long sleepOneThird(String s) throws InterruptedException { | |
long pid = ProcessHandle.current().pid(); | |
// for (int i = 0; i < 60; i++) { | |
for (int i = 0; i < 5; i++) { | |
System.out.println("[" + pid + ", " + s + "]" + " Sleeping for 1s..."); | |
Thread.sleep(1000); | |
} | |
return Long.valueOf(pid); | |
} | |
private void handle() throws ExecutionException, InterruptedException { | |
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { | |
Supplier<Long> task1 = scope.fork(() -> sleepOneThird("task1")); | |
Supplier<Long> task2 = scope.fork(() -> sleepOneThird("task2")); | |
Supplier<Long> task3 = scope.fork(() -> sleepOneThird("task3")); | |
scope.join() | |
.throwIfFailed(); | |
} | |
} | |
public void print() { | |
try { | |
handle(); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
class StructuredConcurrencyThirdPreview { | |
// Java 20 Preview | |
private <T> T getCallableTaskListResult(List<Callable<T>> callableTaskList) throws InterruptedException, ExecutionException { | |
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<T>()) { | |
for (Callable<T> callableTask : callableTaskList) { | |
scope.fork(callableTask); | |
try { | |
System.out.println(callableTask.call()); | |
} catch (Exception ex) { | |
// ex.printStackTrace(); | |
System.out.println(ex.getMessage()); | |
} | |
} | |
scope.join(); | |
return scope.result(); | |
} | |
} | |
// Java 20 Preview | |
private void callableTaskListResult() { | |
Callable<String> callableAlpha = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Alpha"; }; | |
Callable<String> callableBeta = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Beta"; }; | |
Callable<String> callableGamma = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Gamma"; }; | |
Callable<String> callableDelta = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Delta"; }; | |
Callable<String> callableEpsilon = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Epsilon"; }; | |
List<Callable<String>> callableTaskList = new ArrayList<>(Arrays.asList( callableAlpha, callableBeta, callableGamma, callableDelta, callableEpsilon)); | |
try { | |
System.out.println("Callable Task List Result: " + getCallableTaskListResult(callableTaskList)); | |
} catch (InterruptedException | ExecutionException ex) { | |
// ex.printStackTrace(); | |
System.out.println(ex.getMessage()); | |
} | |
} | |
private String randomUUID() { | |
try { | |
Thread.sleep(Duration.ofSeconds(2L)); | |
} | |
catch (InterruptedException ex) { | |
// ex.printStackTrace(); | |
System.out.println(ex.getMessage()); | |
} | |
return UUID.randomUUID().toString(); | |
} | |
private Integer randomNext() { | |
try { | |
Thread.sleep(Duration.ofSeconds(2L)); | |
} | |
catch (InterruptedException ex) { | |
// ex.printStackTrace(); | |
System.out.println(ex.getMessage()); | |
} | |
return new Random().nextInt(Integer.MIN_VALUE, Integer.MAX_VALUE); | |
} | |
// Java 21 Preview | |
private String getRandom() { | |
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { | |
// Java 21 Preview | |
Subtask<String> randomUUID = scope.fork(() -> this.randomUUID()); | |
Subtask<Integer> randomNext = scope.fork(() -> this.randomNext()); | |
try { | |
scope.join(); | |
} catch (InterruptedException ex) { | |
// ex.printStackTrace(); | |
System.out.println(ex.getMessage()); | |
} | |
return String.format("Random UUID = %s, Random Number = %d", randomUUID.get(), randomNext.get()); | |
} | |
} | |
// Java 21 Preview | |
private List scopeXStructuredTaskScope() { | |
Callable<String> callableAlpha = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Alpha"; }; | |
Callable<String> callableBeta = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Beta"; }; | |
Callable<String> callableGamma = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Gamma"; }; | |
Callable<String> callableDelta = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Delta"; }; | |
Callable<String> callableEpsilon = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Epsilon"; }; | |
List<Callable<String>> callableTaskList = new ArrayList<>(Arrays.asList( callableAlpha, callableBeta, callableGamma, callableDelta, callableEpsilon)); | |
// Java 21 Preview | |
try (var scope = new ScopeX<>()) { | |
// try (var scope = new StructuredTaskScope<>()) { | |
List<Subtask<String>> subtasks = callableTaskList.stream().map(scope::fork).toList(); | |
try { | |
scope.join(); | |
} catch (InterruptedException ex) { | |
// ex.printStackTrace(); | |
System.out.println(ex.getMessage()); | |
} | |
// System.out.println(scope.<String>results().toList()); | |
return scope.results().toList(); | |
} // close | |
} | |
// Java 21 Preview | |
private List collectingScopeStructuredTaskScope() { | |
Callable<String> callableAlpha = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Alpha"; }; | |
Callable<String> callableBeta = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Beta"; }; | |
Callable<String> callableGamma = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Gamma"; }; | |
Callable<String> callableDelta = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Delta"; }; | |
Callable<String> callableEpsilon = () -> { Thread.sleep(Duration.ofSeconds(1L)); return "Epsilon"; }; | |
List<Callable<String>> callableTaskList = new ArrayList<>(Arrays.asList( callableAlpha, callableBeta, callableGamma, callableDelta, callableEpsilon)); | |
// Java 21 Preview | |
try (var scope = new ScopeY<String>()) { | |
// try (var scope = new StructuredTaskScope<String>()) { | |
List<Subtask<String>> subtasks = callableTaskList.stream().map(scope::fork).toList(); | |
try { | |
scope.join(); | |
} catch (InterruptedException ex) { | |
// ex.printStackTrace(); | |
System.out.println(ex.getMessage()); | |
} | |
// scope.<String>completedSuccessfully().forEach(x -> System.out.println( x.get())); | |
return scope.<String>completedSuccessfully().map(x -> x.get()).toList(); | |
} // close | |
} | |
public void print() { | |
System.out.println("# 10 # 480: Structured Concurrency (Third Preview)"); | |
System.out.println("StructuredTaskScope Callable..."); | |
callableTaskListResult(); | |
System.out.println("StructuredTaskScope Subtask..."); | |
System.out.println(getRandom()); | |
System.out.println("ScopeX<T> extends StructuredTaskScope<T>..."); | |
System.out.println(scopeXStructuredTaskScope()); | |
System.out.println("CollectingScope<T> extends StructuredTaskScope<T>..."); | |
System.out.println(collectingScopeStructuredTaskScope()); | |
System.out.println("Short Circuiting Pattern..."); | |
var patternShortCircuiting = new ShortCircuitingPattern(); | |
patternShortCircuiting.randomTasks(); | |
System.out.println("Short Circuiting Pattern Observable..."); | |
var observableShortCircuitingPattern = new ShortCircuitingPatternObservable(); | |
observableShortCircuitingPattern.print(); | |
} | |
} | |
class Task { | |
private final static ScopedValue<String> INNER_SCOPE = ScopedValue.newInstance(); | |
public void execute() { | |
System.out.println("Before All Scopes OUTER_SCOPE: " + ScopedValuesThirdPreview.OUTER_SCOPE.get()); | |
// Nested Scope | |
ScopedValue.where(INNER_SCOPE, "Inner Scople Run").run(() -> { | |
var outerScopeGet = ScopedValuesThirdPreview.OUTER_SCOPE.get(); | |
var innerScopeGet = INNER_SCOPE.get(); | |
System.out.println("Inner OUTER_SCOPE: " + outerScopeGet); | |
System.out.println("Inner INNER_SCOPE: " + innerScopeGet); | |
}); | |
// Rebounded Scope | |
ScopedValue.where(ScopedValuesThirdPreview.OUTER_SCOPE, "Rebounded Outer Scope Run").run(() -> { | |
var reboundedOuterScopeGet = ScopedValuesThirdPreview.OUTER_SCOPE.get(); | |
System.out.println("Rebounded OUTER_SCOPE: " + reboundedOuterScopeGet); | |
}); | |
System.out.println("After All Scopes OUTER_SCOPE: " + ScopedValuesThirdPreview.OUTER_SCOPE.get()); | |
} | |
} | |
class ScopedValuesThirdPreview { | |
private static final ScopedValue<Integer> RANDOM = ScopedValue.newInstance(); | |
public static final ScopedValue<String> OUTER_SCOPE = ScopedValue.newInstance(); | |
private void scopedValueWithStructuredTaskScope() { | |
// try (StructuredTaskScope<Object> scope = new StructuredTaskScope<>()) { | |
try (var scope = new StructuredTaskScope<>()) { | |
for (int i = 0; i< 10; i++) { | |
// Java 21 Preview | |
Subtask<Integer> task = scope.fork(() -> { | |
int randomNumber = ThreadLocalRandom.current().nextInt(1, 101); | |
ScopedValue.where(RANDOM, randomNumber).run(() -> { | |
System.out.println(String.format("ScopedValue With StructuredTaskScope: Thread %s: Random Number: %d", Thread.currentThread().threadId(), RANDOM.get())); | |
}); | |
return null; | |
}); | |
} | |
try { | |
scope.join(); | |
} catch (InterruptedException ex) { | |
// ex.printStackTrace(); | |
System.out.println(ex.getMessage()); | |
} | |
} | |
} | |
private void scopedValue() { | |
for (int i = 0; i < 10; i++) { | |
Thread scopedValueThread = new Thread(() -> { | |
int randomNumber = ThreadLocalRandom.current().nextInt(1, 101); | |
ScopedValue.where(RANDOM, randomNumber).run(() -> { | |
System.out.println(String.format("ScopedValue: Thread %s: Random Number: %d", Thread.currentThread().getName(), RANDOM.get())); | |
}); | |
}); | |
scopedValueThread.start(); | |
try { | |
scopedValueThread.join(); | |
} catch (InterruptedException ex) { | |
// ex.printStackTrace(); | |
System.out.println(ex.getMessage()); | |
} | |
} | |
} | |
private void scopedValueTask() { | |
ScopedValue.where(OUTER_SCOPE, "Outer Scope Run").run(() -> { | |
var tsk = new Task(); | |
tsk.execute(); | |
}); | |
} | |
public void print() { | |
System.out.println("# 11 # 481: Scoped Values (Third Preview)"); | |
System.out.println("ScopedValue..."); | |
scopedValue(); | |
System.out.println("ScopedValue With StructuredTaskScope..."); | |
scopedValueWithStructuredTaskScope(); | |
System.out.println("Scoped Value Task..."); | |
scopedValueTask(); | |
} | |
} | |
class A { | |
int i; | |
A() { | |
// Java 23 Preview // error: cannot reference this before supertype constructor has been called // 3 errors | |
// Pre-Java 23 Preview // error: call to super must be first statement in constructor // 1 error | |
// this.i++; // Error | |
// var x = this.i; // Error | |
// this.hashCode(); // Error | |
// System.out.print(this); // Error | |
super(); | |
} | |
} | |
class B { | |
int b; | |
class C { | |
int c; | |
C() { | |
// Java 23 Preview // no error | |
// Pre-Java 23 Preview // error: call to super must be first statement in constructor // 1 error | |
B.this.b++; // Allowed - enclosing instance // Java 23 Preview | |
// Java 23 Preview // error: cannot reference this before supertype constructor has been called | |
// Pre-Java 23 Preview // error: call to super must be first statement in constructor | |
// C.this.c++; // Error - same instance | |
super(); | |
} | |
} | |
} | |
class D { | |
int i; | |
void m() { } | |
} | |
class E extends D { | |
E() { | |
// Java 23 Preview // error: cannot reference super before supertype constructor has been called | |
// Pre-Java 23 Preview // error: call to super must be first statement in constructor | |
// super.i++; // Error | |
// var x = super.i; // Error | |
// super.m(); // Error | |
super(); | |
} | |
} | |
class F { | |
int i; | |
F() { | |
// Java 23 Preview // error: cannot reference this before supertype constructor has been called // 2 errors | |
// Pre-Java 23 Preview // error: call to super must be first statement in constructor // 1 error | |
// i++; // Error | |
// hashCode(); // Error | |
super(); | |
} | |
} | |
class Outer { | |
int i; | |
void hello() { | |
System.out.println("Hello"); | |
} | |
class Inner { | |
Inner() { | |
// Java 23 Preview // no error | |
// Pre-Java 23 Preview // error: call to super must be first statement in constructor // 1 error | |
var x = i; // Allowed - implicitly refers to field of enclosing instance | |
var y = Outer.this.i; // Allowed - explicitly refers to field of enclosing instance | |
hello(); // Allowed - enclosing instance method // Java 23 Preview | |
super(); | |
} | |
} | |
} | |
class Out { | |
class In { } | |
Out() { | |
// Java 23 Preview // error: cannot reference super before supertype constructor has been called | |
// Pre-Java 23 Preview // error: call to super must be first statement in constructor | |
// new In(); // Error - 'this' is enclosing instance | |
// var x = new In(); // Error | |
// var y = this.new Inn(); // Error | |
super(); | |
} | |
} | |
class O { | |
class V { } | |
class U { | |
U() { | |
// Java 23 Preview // no error | |
// Pre-Java 23 Preview // error: call to super must be first statement in constructor | |
var tmp = new V() { }; // Allowed // Java 23 Preview | |
super(); | |
} | |
} | |
} | |
class X { | |
X() { } | |
X(Object instance) { } | |
} | |
class W<T> extends X { | |
W() { | |
// Java 23 Preview // error: cannot reference this before supertype constructor has been called | |
// Pre-Java 23 Preview // error: cannot reference this before supertype constructor has been called | |
// super(this); // Error - refers to 'this' | |
} | |
@SuppressWarnings({ "unchecked" }) | |
W(List<?> list) { | |
// Java 23 Preview // no error | |
// Pre-Java 23 Preview // no error | |
super((T)list.get(0)); // Allowed - refers to 'T' but not 'this' // Java 23 Preview // Pre-Java 23 Preview // warning: [unchecked] unchecked cast | |
} | |
} | |
class Super { | |
Super() { overriddenMethod(); } | |
void overriddenMethod() { System.out.println("hello"); } | |
} | |
// Early assignment to fields | |
// Accessing fields of the current instance is disallowed in an early construction context, but what about assigning to fields of the current instance while it is still under construction? | |
// Allowing such assignments would be useful as a way for a constructor in a subclass to defend against a constructor in a superclass seeing uninitialized fields in the subclass. | |
// This can occur when a constructor in a superclass invokes a method in the superclass that is overridden by a method in the subclass. | |
// Although the Java language allows constructors to invoke overridable methods, it is considered bad practice: Item 19 of Effective Java (Third Edition) advises that "Constructors must not invoke overridable methods." To see why it is considered bad practice, consider the following class hierarchy: | |
class Superb { | |
Superb() { overriddenMethod(); } | |
void overriddenMethod() { System.out.println("hello"); } | |
} | |
class Sub extends Superb { | |
final int x; | |
Sub(int x) { | |
/* super(); */ // Super constructor implicit invocation // Before assignment | |
this.x = x; | |
super(); // Super constructor explicit invocation // After assignment | |
} | |
@Override | |
void overriddenMethod() { System.out.println(x); } | |
} | |
class FlexibleConstructorBodiesSecondPreview { | |
public void print() { | |
System.out.println("# 12 # 482: Flexible Constructor Bodies (Second Preview)"); | |
// Implicit invocation | |
// This actually prints 0 and not 482 because the Super constructor is implicitly invoked before the field assignment in the Sub constructor body. | |
// The Super constructor then invokes overriddenMethod, causing that method in Sub to run before the Sub constructor body has had a chance to assign 42 to the field. | |
// As a result, the method in Sub sees the default value of the field, which is 0. | |
// new Sub(482); // Without // Super constructor explicit invocation // After assignment | |
// Solve the conundrum by allowing the Sub constructor to initialize the field in Sub before invoking the Super constructor explicitly. | |
// Then invoke the Super constructor explicitly | |
new Sub(482); | |
} | |
} | |
class SystemProperties { | |
public void print() { | |
System.out.println(String.format("OS Name: %s", System.getProperty("os.name"))); | |
System.out.println(String.format("OS Version: %s", System.getProperty("os.version"))); | |
System.out.println(String.format("OS Architecture: %s", System.getProperty("os.arch"))); | |
System.out.println(String.format("Java Version: %s", System.getProperty("java.version"))); | |
// System.getProperties().list(System.out); | |
} | |
} | |
/******************************************************************************/ | |
// # 3 # 467: Markdown Documentation Comments | |
/******************************************************************************/ | |
// $ javadoc --enable-preview --source 23 --add-modules=jdk.incubator.vector Java23.java -tag "impl.Spec" -d "./output-files" | |
// $ rm -rf output-files | |
/******************************************************************************/ | |
/******************************************************************************/ | |
// # 10 # 480: Structured Concurrency (Third Preview) | |
/******************************************************************************/ | |
// While the class ShortCircuitingPatternObservable is running, create a thread dump by running the following command in a different console, where <pid> is the process ID of the running Java process. | |
// The thread dump output file shows the StructuredTaskScope with the threads of its forked subtasks in an array. | |
// The thread dump also shows the reference to the parent of the StructuredTaskScope so that the structure of the program can be reconstituted from the thread dump. | |
// Check the class ShortCircuitingPatternObservable for sleepOneSecond | |
// $ Terminal New Window | |
// $ jcmd <pid> Thread.dump_to_file -format=json output_file.txt | |
// use -overwrite to overwrite | |
// $ jcmd <pid> Thread.dump_to_file -format=json output_file.txt -overwrite | |
/******************************************************************************/ | |
// java --enable-preview --source 23 --enable-native-access=ALL-UNNAMED --add-modules=jdk.incubator.vector Java23.java && java Program | |
/* | |
WARNING: Using incubator modules: jdk.incubator.vector | |
OS Name: Linux | |
OS Version: 6.6.50-05083-g5a8e7e69b744 | |
OS Architecture: amd64 | |
Java Version: 23.0.2 | |
# 1 # 455: Primitive Types in Patterns, instanceof, and switch (Preview) | |
unknown status: 0 | |
warning | |
cover all possible input values: -9 | |
The following table denotes the conversions that are permitted between primitive types. | |
Unconditionally exact conversions are denoted with the symbol ɛ. | |
The symbol ≈ means the identity conversion, ω means a widening primitive conversion, η means a narrowing primitive conversion, and ωη means a widening and narrowing primitive conversion. | |
The symbol — means no conversion is allowed. | |
o → byte short char int long float double boolean | |
From ↓ | |
byte ≈ ɛ ωη ɛ ɛ ɛ ɛ — | |
short η ≈ η ɛ ɛ ɛ ɛ — | |
char η η ≈ ɛ ɛ ɛ ɛ — | |
int η η η ≈ ɛ ω ɛ — | |
long η η η η ≈ ω ω — | |
float η η η η η ≈ ɛ — | |
double η η η η η η ≈ — | |
boolean — — — — — — — ≈ | |
byte b = 42 instanceof int: true | |
int int i = 42 instanceof byte: true | |
int i = 1000 instanceof byte: false | |
int i = 16_777_217 instanceof float: false | |
int i = 16_777_217 instanceof double: true | |
int i = 16_777_217 instanceof Integer: true | |
int i = 16_777_217 instanceof Number: true | |
float f = 1000.0f instanceof byte: false | |
float f = 1000.0f instanceof int: true | |
float f = 1000.0f instanceof double: true | |
float f = 1000.0f instanceof byte: false | |
float f = 1000.0f instanceof int: true | |
float f = 1000.0f instanceof float: true | |
Integer ii = 1000 instanceof int: true | |
Integer ii = 1000 instanceof float: true | |
Integer ii = 1000 instanceof double: true | |
int ii = 16_777_217 instanceof float: false | |
int ii = 16_777_217 instanceof double: true | |
Exhaustive switch: 0 | |
Expanded primitive support in switch: 3.4028235E38 | |
Exhaustive boolean switch: Truthy | |
# 2 # 466: Class-File API (Second Preview) | |
# 3 # 467: Markdown Documentation Comments | |
Note: Custom tags that could override future standard tags: @implSpec. | |
To avoid potential overrides, use at least one period character (.) in custom tag names. | |
# 4 # 469: Vector API (Eighth Incubator) | |
Support the ARM Scalar Vector Extension (SVE) platform. | |
Scalar Computation | |
[-13.0, -36.649998] | |
Vector Computation | |
[-13.0, -36.649998] | |
An API to express vector computations that reliably compile at runtime to optimal vector instructions on supported CPU architectures, thus achieving performance superior to equivalent scalar computations. | |
[-13.0, -36.649998] | |
# 5 # 473: Stream Gatherers (Second Preview) | |
Record: new BiggestInt(555): BiggestInt[limit=555] | |
Gatherer (400, 300, 200, 777, 600, 800, 1000) gather(new BiggestInt(555) leftMax vs. rightMax findFirst | |
777 | |
Gatherer (400, 300, 200, 777, 600, 800, 1000) gather(new BiggestInt(555) parallel leftMax vs. rightMax findFirst | |
777 | |
Gatherers with Factory Methods (400, 300, 200, 777, 600, 800, 1000) gather(biggestInt(555)) leftMax vs. rightMax parallel | |
Processing 300 | |
Processing 200 | |
Processing 400 | |
Processing 1000 | |
Processing 800 | |
Processing 777 | |
777 | |
Built-In Gatherers | |
Gatherers.fold .forEach(): (2, 4, 6, 8): 6, (x, y) -> x * y) | |
2304 | |
Gatherers.fold .findFirst().get(): (2, 4, 6, 8): Comma Space Separated | |
2, 4, 6, 8 | |
Gatherers.mapConcurrent .forEach(): (2, 4, 6, 8): maxConcurrency, x -> x * 2 | |
4 | |
8 | |
12 | |
16 | |
Gatherers.mapConcurrent .findFirst().get(): (2, 4, 6, 8): maxConcurrency, x -> x * 2 | |
4 | |
Gatherers.scan .forEach(): (2, 4, 6, 8): 6, (x, y) -> x * y | |
12 | |
48 | |
288 | |
2304 | |
Gatherers.windowFixed: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10): windowFixed(3) | |
[1, 2, 3] | |
[4, 5, 6] | |
[7, 8, 9] | |
[10] | |
Gatherers.windowSliding: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10): windowSliding(3) | |
[1, 2, 3] | |
[2, 3, 4] | |
[3, 4, 5] | |
[4, 5, 6] | |
[5, 6, 7] | |
[6, 7, 8] | |
[7, 8, 9] | |
[8, 9, 10] | |
Composing Gatherers with Gatherer.andThen(Gatherer): scan.andThen(fold): (1, 2, 3, 4, 5, 6, 7, 8, 9, 10): 100, (x, y) -> x + y) | |
101; 103; 106; 110; 115; 121; 128; 136; 145; 155 | |
# 6 # 471: Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal | |
Deprecate the memory-access methods in sun.misc.Unsafe for removal in a future release. These unsupported methods have been superseded by standard APIs, namely the VarHandle API (JEP 193, JDK 9) and the Foreign Function & Memory API (JEP 454, JDK 22). We strongly encourage library developers to migrate from sun.misc.Unsafe to supported replacements, so that applications can migrate smoothly to modern JDK releases. | |
On-heap memory access: true | |
On-heap memory access volatile: [0, 0, 0, 0, 0, 4, 0, 0, 0, 0] | |
Off-heap memory access: [0, 0] | |
# 7 # 474: ZGC: Generational Mode by Default | |
Make Generational ZGC the default mode of ZGC by changing the default value of the ZGenerational option from false to true. Deprecate the non-generational mode by deprecating the ZGenerational option. | |
# 8 # 476: Module Import Declarations (Preview) | |
A module import declaration has the form | |
import module M; | |
It imports, on demand, all of the public top-level classes and interfaces in | |
The packages exported by the module M to the current module, and | |
The packages exported by the modules that are read by the current module due to reading the module M. | |
The second clause allows a program to use the API of a module, which might refer to classes and interfaces from other modules, without having to import all of those other modules. | |
# 9 # 477: Implicitly Declared Classes and Instance Main Methods (Third Preview)To simplify the writing of interactive small programs, we make three methods available for use in the body of every implicit class: | |
public static void println(Object obj); | |
public static void print(Object obj); | |
public static String readln(String prompt); | |
We achieve this effect by declaring a new top-level class in the java.io package named, simply, IO. | |
It declares the above three static methods for textual I/O with the console, and nothing else. | |
Every implicitly declared class automatically imports these static methods, as if the declaration | |
import static java.io.IO.*; | |
appears at the start of every source file containing an implicit class. | |
The new class java.io.IO is a preview API in JDK 23. | |
Every implicitly declared class can be considered to implicitly import the java.base module, as if the declaration | |
import module java.base; | |
appears at the start of every source file containing an implicit class. | |
# 10 # 480: Structured Concurrency (Third Preview) | |
StructuredTaskScope Callable... | |
Alpha | |
Beta | |
Gamma | |
Delta | |
Epsilon | |
Callable Task List Result: Alpha | |
StructuredTaskScope Subtask... | |
Random UUID = c35c5e8c-03c8-4c8e-9d52-3cc5d6b9d7cc, Random Number = 651594773 | |
ScopeX<T> extends StructuredTaskScope<T>... | |
[Alpha, Beta, Gamma, Delta, Epsilon] | |
CollectingScope<T> extends StructuredTaskScope<T>... | |
[Alpha, Gamma, Beta, Delta, Epsilon] | |
Short Circuiting Pattern... | |
Running handle ShutdownOnFailure... | |
Duration: 463 | |
Duration: 66 | |
Duration: 257 | |
Duration: 278 | |
Duration: 870 | |
Java23$ShortCircuitingPattern$TooSlowException: Duration 870 greater than threshold 850 | |
Running handle ShutdownOnSuccess<T>... | |
Duration: 63 | |
Duration: 943 | |
Duration: 451 | |
Duration: 363 | |
Duration: 329 | |
First task to finish: 63 | |
Running handle Successful And Failed Tasks... | |
Duration: 625 | |
Duration: 851 | |
Duration: 842 | |
Duration: 448 | |
Duration: 806 | |
Total duration: 448 | |
Duration 625 greater than threshold 500 | |
Duration 851 greater than threshold 500 | |
Duration 842 greater than threshold 500 | |
Duration 806 greater than threshold 500 | |
Short Circuiting Pattern Observable... | |
[1573, task2] Sleeping for 1s... | |
[1573, task3] Sleeping for 1s... | |
[1573, task1] Sleeping for 1s... | |
[1573, task2] Sleeping for 1s... | |
[1573, task3] Sleeping for 1s... | |
[1573, task1] Sleeping for 1s... | |
[1573, task2] Sleeping for 1s... | |
[1573, task3] Sleeping for 1s... | |
[1573, task1] Sleeping for 1s... | |
[1573, task2] Sleeping for 1s... | |
[1573, task3] Sleeping for 1s... | |
[1573, task1] Sleeping for 1s... | |
[1573, task2] Sleeping for 1s... | |
[1573, task1] Sleeping for 1s... | |
[1573, task3] Sleeping for 1s... | |
# 11 # 481: Scoped Values (Third Preview) | |
ScopedValue... | |
ScopedValue: Thread Thread-0: Random Number: 47 | |
ScopedValue: Thread Thread-1: Random Number: 49 | |
ScopedValue: Thread Thread-2: Random Number: 12 | |
ScopedValue: Thread Thread-3: Random Number: 89 | |
ScopedValue: Thread Thread-4: Random Number: 83 | |
ScopedValue: Thread Thread-5: Random Number: 51 | |
ScopedValue: Thread Thread-6: Random Number: 50 | |
ScopedValue: Thread Thread-7: Random Number: 6 | |
ScopedValue: Thread Thread-8: Random Number: 81 | |
ScopedValue: Thread Thread-9: Random Number: 99 | |
ScopedValue With StructuredTaskScope... | |
ScopedValue With StructuredTaskScope: Thread 74: Random Number: 12 | |
ScopedValue With StructuredTaskScope: Thread 73: Random Number: 6 | |
ScopedValue With StructuredTaskScope: Thread 75: Random Number: 21 | |
ScopedValue With StructuredTaskScope: Thread 76: Random Number: 16 | |
ScopedValue With StructuredTaskScope: Thread 77: Random Number: 17 | |
ScopedValue With StructuredTaskScope: Thread 78: Random Number: 78 | |
ScopedValue With StructuredTaskScope: Thread 79: Random Number: 97 | |
ScopedValue With StructuredTaskScope: Thread 80: Random Number: 79 | |
ScopedValue With StructuredTaskScope: Thread 81: Random Number: 93 | |
ScopedValue With StructuredTaskScope: Thread 82: Random Number: 95 | |
Scoped Value Task... | |
Before All Scopes OUTER_SCOPE: Outer Scope Run | |
Inner OUTER_SCOPE: Outer Scope Run | |
Inner INNER_SCOPE: Inner Scople Run | |
Rebounded OUTER_SCOPE: Rebounded Outer Scope Run | |
After All Scopes OUTER_SCOPE: Outer Scope Run | |
# 12 # 482: Flexible Constructor Bodies (Second Preview) | |
482 | |
Java Version: 23.0.2 | |
*/ | |
// Credits | |
/* | |
https://openjdk.org/ | |
https://oracle.com/java/ | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment