Key Language Features Introduced in JDK 17
Yield Keyword in Switch Expressions
Starting from Java 13, the yield keyword enhances switch expressions by allowing them to return values. This feature simplifies code by eliminating the need for explicit break statements and separate variable assignments.
Traditional switch statement:
public class Example {
public static void main(String[] args) {
int result = 0;
String input = "three";
switch (input) {
case "one":
result = 1;
break;
case "two":
result = 2;
break;
case "three":
result = 3;
break;
default:
result = -1;
break;
}
System.out.println(result);
}
}
Using arrow syntax for concise switch expressions:
public class Example {
public static void main(String[] args) {
String input = "three";
int result = switch (input) {
case "one" -> 1;
case "two" -> 2;
case "three" -> 3;
default -> -1;
};
System.out.println(result);
}
}
Using yield for explicit value return in switch blocks:
public class Example {
public static void main(String[] args) {
String input = "three";
int result = switch (input) {
case "one":
yield 1;
case "two":
yield 2;
case "three":
yield 3;
default:
yield -1;
};
System.out.println(result);
}
}
Local Variable Type Inference with var
Introduced in Java 10, the var keyword enables local variable type inference, reducing verbosity by allowing the compiler to deduce types from initializers.
Example usage:
public class Example {
public static void main(String[] args) {
var text = "example"; // Inferred as String
var count = 10; // Inferred as int
System.out.println(text + " " + count);
}
}
Restrictions on var:
- Cannot be used for field declarations.
- Cannot be used for method parameters.
- Cannot be used for method return types.
- Variables must be initialized; null initialization is not allowed.
Sealed Classes with sealed Keyword
JDK 17 introduces sealed classes via the sealed keyword, which restricts inheritance to explicitly permitted subclasses, providing more control than final classes.
Syntax and usage:
sealed class Base permits Derived1, Derived2, Derived3 {
// Base class body
}
non-sealed class Derived1 extends Base {
// Can be further extended
}
final class Derived2 extends Base {
// Cannot be extended
}
sealed class Derived3 extends Base permits SubDerived {
// Must have subclasses
}
non-sealed class SubDerived extends Derived3 {
// No restrictions
}
Key points:
- A sealed class must have atleast one direct subclass.
- Subclasses must be declared as
final,sealed, ornon-sealed. - The
permitsclause specifies allowed subclasses; if omitted, any class can extend it. - Unlike
finalclasses, sealed classes require subclasses.
Private Methods in Interfaces
Since Java 9, interfaces support private methods, which are useful for encapsulating helper logic within default methods without exposing them to implementing classes.
Example:
interface SampleInterface {
void primaryMethod();
default void helperMethod() {
System.out.println("Helper output");
internalLogic();
}
private void internalLogic() {
System.out.println("Private method output");
}
}
class Implementation implements SampleInterface {
@Override
public void primaryMethod() {
// Implementation
}
}
Pattern Matching for instanceof
Enhanced in JDK 16, pattern matching with instanceof simplifies type checking and casting by combining them into a single expression.
Traditional approach:
class Animal {
public void eat() {}
}
class Canine extends Animal {
@Override
public void eat() {
System.out.println("Canine eating");
}
public void run() {
System.out.println("Canine running");
}
}
public class Test {
public static void main(String[] args) {
Animal animal = new Canine();
if (animal instanceof Canine) {
Canine canine = (Canine) animal;
canine.run();
}
}
}
Using pattern matching:
public class Test {
public static void main(String[] args) {
Animal animal = new Canine();
if (animal instanceof Canine canine) {
canine.run();
}
}
}