JDK new features:修订间差异
第92行: | 第92行: | ||
== Record Patterns == | == Record Patterns == | ||
Record Patterns extends the pattern matching capabilities of Java beyond simple type patterns to match and deconstruct Record values. It supports nesting to enable declarative, data focused programming. | |||
<syntaxhighlight lang="java"> | |||
interface Point { } | |||
record Point2D(int x, int y) implements Point { } | |||
enum Color { RED, GREEN, BLUE } | |||
record ColoredPoint(Point p, Color c) { } | |||
Object r = new ColoredPoint(new Point2D(3, 4), Color.GREEN); | |||
</syntaxhighlight> | |||
Note, that while we use a Point2D to construct r, ColoredPoint accepts other Point implementations as well. | |||
Without pattern matching, we'd need two explicit type checks to detect if object r is a ColoredPoint that holds Point2D, and also quite some work to extract the values x, y, and c: | |||
<syntaxhighlight lang="java"> | |||
if (r instanceof ColoredPoint) { | |||
ColoredPoint cp = (ColoredPoint) r; | |||
if (cp.p() instanceof Point2D) { | |||
Point2D pt = (Point2D) cp.p(); | |||
int x = pt.x(); | |||
int y = pt.y(); | |||
Color c = cp.c(); | |||
// work with x, y, and c | |||
} | |||
} | |||
</syntaxhighlight> | |||
== Unnamed Patterns and Variables (Preview) == | == Unnamed Patterns and Variables (Preview) == |
2024年10月23日 (三) 06:24的版本
JDK 22
JDK 21
Pattern Matching for switch
Previously, switch was very limited: the cases could only test exact equality, and only for values of a few types: numbers, Enum types and Strings.
This feature enhances switch to work on any type and to match on more complex patterns.
These additions are backwards compatible, switch with the traditional constants work just as before, for example, with Enum values:
enum Status { Normal, Deleted }
public int getStatus(Status s) {
return switch(s) {
case Normal -> 0;
case Deleted -> -1;
};
}
However, now it also works with type patterns introduced by JEP 394: Pattern Matching for instanceof:
class Item {}
class Text extends Item {}
class Image extends Item {
public String getImageType() { return "png"; }
}
public void printItem(Item item) {
var msg = switch(item) {
case Text ignored -> "Text";
case Image ignored -> "Image";
default -> "Unknow item";
};
System.out.println(msg);
}
A pattern supports guards, written as type pattern when guard expression:
var msg = switch(item) {
case Text ignored -> "Text";
case Image img when img.size > 1024 -> "Large Image";
case Image ignored -> "Image";
default -> "Unknow item";
};
Similarly to the type patterns in if conditions, the scope of the pattern variables are flow sensitive. Generally it works just as you'd expect, but there are many rules and edge cases involved.
Switch expressions always had to be exhaustive, in other words, they have to cover all possible input types. This is still the case with the new patterns, the Java compiler emits an error when the switch is incomplete.
Switch can now also match null values. Traditionally, when a null value was supplied to a switch, it threw a NullPointerException. For backwards compatibility, this is still the case when there's no explicit null pattern defined. However, now an explicit case for null can be added:
var msg = switch(item) {
// without this, a NullPointerException throws if item is null.
case null -> "Empty";
case Text ignored -> "Text";
case Image img when img.size > 1024 -> "Large Image";
case Image ignored -> "Image";
default -> "Unknow item";
};
This feature synergizes well with enums, Sealed Classes and generics. If there's only a fixed set of possible alternatives that exist, the default case can be omitted. Also, this feature helps a lot to maintain the integrity of the codebase when the domain is extended — for example, with a new constant in the enum. Due to the exhaustiveness check, all related switch expressions will yield a compiler error where the default case is not handled.
sealed interface I<T> permits A, B {}
final class A<X> implements I<String> {}
final class B<Y> implements I<Y> {}
static int testGenericSealedExhaustive(I<Integer> i) {
return switch (i) {
case B<Integer> bi -> 42;
};
}
Exhaustiveness is checked at compile time but if at runtime a new implementation pops up (e.g. from a separate compilation), the compiler also inserts a synthetic default case that throws a MatchException.
The compiler also performs the opposite of the exhaustiveness check: it emits an error when a case completely dominates another.
case Image ignored -> "Image";
// Label is dominated by a preceding case label 'Image ignored'
case Image img when img.size > 1024 -> "Large Image";
For readability reasons, the dominance checking forces constant case labels to appear before the corresponding type-based pattern.
Record Patterns
Record Patterns extends the pattern matching capabilities of Java beyond simple type patterns to match and deconstruct Record values. It supports nesting to enable declarative, data focused programming.
interface Point { }
record Point2D(int x, int y) implements Point { }
enum Color { RED, GREEN, BLUE }
record ColoredPoint(Point p, Color c) { }
Object r = new ColoredPoint(new Point2D(3, 4), Color.GREEN);
Note, that while we use a Point2D to construct r, ColoredPoint accepts other Point implementations as well.
Without pattern matching, we'd need two explicit type checks to detect if object r is a ColoredPoint that holds Point2D, and also quite some work to extract the values x, y, and c:
if (r instanceof ColoredPoint) {
ColoredPoint cp = (ColoredPoint) r;
if (cp.p() instanceof Point2D) {
Point2D pt = (Point2D) cp.p();
int x = pt.x();
int y = pt.y();
Color c = cp.c();
// work with x, y, and c
}
}
Unnamed Patterns and Variables (Preview)
String Templates (Preview)
JDK 17
JEP 409: Sealed Classes
Sealed Classes have been added to the Java Language. Sealed classes and interfaces restrict which other classes or interfaces may extend or implement them.
Sealed Classes were proposed by JEP 360 and delivered in JDK 15 as a preview feature. They were proposed again, with refinements, by JEP 397 and delivered in JDK 16 as a preview feature. Now in JDK 17, Sealed Classes are being finalized with no changes from JDK 16.
For further details, see JEP 409.[1]