Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Key Language Features Introduced in JDK 17

Tech 2

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, or non-sealed.
  • The permits clause specifies allowed subclasses; if omitted, any class can extend it.
  • Unlike final classes, 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();
        }
    }
}
Tags: JDK 17

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.