Java 12 to 17 Features
New school rules are often tried for a term before they become permanent, so teachers and students can point out problems first. From Java 12 onwards, Java started doing the same with language features: a new feature first appears as a preview, gets feedback for a release or two, and only then becomes final. Between Java 12 (March 2019) and Java 17 (September 2021, LTS), this process delivered the biggest language changes since Java 8: switch expressions, text blocks, records, pattern matching and sealed classes. In this lesson, you will get a quick reference to each release, see a tour program, and learn when each feature became final.
When Each Feature Became Final
| Feature | Preview in | Final in | Read more |
|---|---|---|---|
Switch expressions (case X ->, yield) | 12, 13 | 14 | "Switch Expressions" |
Text blocks (""") | 13, 14 | 15 | "Text Blocks in Java" |
Pattern matching for instanceof | 14, 15 | 16 | "Java Instanceof and Pattern Matching" |
| Records | 14, 15 | 16 | "Records in Java" |
| Sealed classes and interfaces | 15, 16 | 17 | "Sealed Classes and Interfaces in Java" |
Other Changes by Release
| Release | Notable additions | Read more |
|---|---|---|
| Java 12 (Mar 2019) | String.indent and transform, Collectors.teeing, compact number formatting ("1K") | "Modern String Methods in Java" |
| Java 13 (Sep 2019) | Previews only (text blocks, yield) | |
| Java 14 (Mar 2020) | Helpful NullPointerException messages that name what was null; JFR event streaming | "Helpful NullPointerException Messages" |
| Java 15 (Sep 2020) | String.formatted, hidden classes, ZGC ready for production, Nashorn JavaScript engine removed | |
| Java 16 (Mar 2021) | Stream.toList(), jpackage for native installers, JDK internals strongly encapsulated by default | "Jpackage in Java: Native Installers" |
| Java 17 (Sep 2021, LTS) | Sealed classes final, new RandomGenerator API, Applet API and Security Manager deprecated for removal, macOS on Apple Silicon |
A Java 12 to 17 Tour
Let's see a program that uses all five headline features together.
Tour17.java▶ Try it
import java.util.List;
public class Tour17 {
sealed interface Fee permits Tuition, Transport {} // 17
record Tuition(String student, int amount) implements Fee {} // 16
record Transport(String student, int km) implements Fee {}
static int amountOf(Fee fee) {
if (fee instanceof Tuition t) { // 16
return t.amount();
} else if (fee instanceof Transport tr) {
return 800 + tr.km() * 20;
}
throw new IllegalArgumentException();
}
static String band(int amount) {
return switch (amount / 5000) { // 14
case 0 -> "low";
case 1, 2 -> "medium";
default -> "high";
};
}
public static void main(String[] args) {
List<Fee> fees = List.of(
new Tuition("Navika", 15000),
new Transport("Srihitha", 12),
new Tuition("Advitha", 9000));
for (Fee f : fees) {
int amount = amountOf(f);
System.out.println(f + " -> " + amount + " (" + band(amount) + ")");
}
String receipt = """
RECEIPT
Student: %s
Amount : %d
""".formatted("Navika", 15000); // 15
System.out.print(receipt);
List<String> names = fees.stream()
.map(f -> f.getClass().getSimpleName())
.toList(); // 16
System.out.println(names);
}
}Output
Tuition[student=Navika, amount=15000] -> 15000 (high)
Transport[student=Srihitha, km=12] -> 1040 (low)
Tuition[student=Advitha, amount=9000] -> 9000 (medium)
RECEIPT
Student: Navika
Amount : 15000
[Tuition, Transport, Tuition]Explanation:
sealed interface Fee permits ...lists every allowed implementation, so the compiler knows all the cases.- Records give
TuitionandTransporta constructor, accessors,equals,hashCodeand the readabletoStringseen in the output, in one line each. instanceof Tuition ttests and casts in one step.- The switch expression returns a value, with
case 1, 2 ->and nobreak. - The text block keeps the receipt's layout, and
formattedfills in the values. Stream.toList()is a shortercollect(Collectors.toList()), and the list it returns is unmodifiable.
Practice
- Easy: Rewrite this old switch as a switch expression:
String r; switch (g) { case 'A': r = "Excellent"; break; case 'B': r = "Good"; break; default: r = "Keep going"; } - Harder: Add a third record
Hostel(String student, int months)toTour17, and add it to thepermitslist. Compile without changingamountOfand read what happens at runtime; then fix it.
Key Takeaways
Was this tutorial helpful?
Lesson 563 of 578