Interview

15 Java 17 Interview Questions and Answers

Prepare for your Java 17 interview with curated questions and answers, covering new features and practical applications.

Java 17, the latest Long-Term Support (LTS) release, brings a host of new features and enhancements that solidify its position as a cornerstone in enterprise-level development. With improvements in performance, security, and modern language features, Java 17 is designed to meet the evolving needs of developers and organizations alike. Its robust ecosystem and extensive libraries make it a versatile choice for a wide range of applications, from web services to large-scale enterprise systems.

This article aims to prepare you for your upcoming Java 17 interview by providing a curated selection of questions and answers. These examples will help you understand the key concepts and practical applications of Java 17, ensuring you are well-prepared to demonstrate your expertise and problem-solving abilities.

Java 17 Interview Questions and Answers

1. Explain how sealed classes work and provide an example scenario where they would be beneficial.

Sealed classes in Java 17 allow you to define a class or interface with a restricted set of subclasses using the sealed keyword and permits clause. This feature is useful for maintaining a controlled and predictable set of subclasses, enhancing code maintainability and security.

Example scenario: In a banking system, you might want to restrict the types of bank accounts to specific ones like SavingsAccount and CheckingAccount. Sealed classes can enforce this restriction.

public sealed class BankAccount permits SavingsAccount, CheckingAccount {
    // common properties and methods
}

public final class SavingsAccount extends BankAccount {
    // specific properties and methods for savings account
}

public final class CheckingAccount extends BankAccount {
    // specific properties and methods for checking account
}

In this example, the BankAccount class is sealed, and only SavingsAccount and CheckingAccount are permitted to extend it, ensuring a controlled class hierarchy.

2. Write a code snippet using pattern matching for instanceof to simplify type casting.

Pattern matching for instanceof in Java 17 allows you to test and cast an object to a given type in a single expression, reducing boilerplate code and enhancing readability.

Example:

public class PatternMatchingExample {
    public static void main(String[] args) {
        Object obj = "Hello, World!";
        
        if (obj instanceof String s) {
            System.out.println(s.toUpperCase());
        } else {
            System.out.println("Not a string");
        }
    }
}

Here, instanceof checks if obj is a String. If true, s is automatically cast to String for use within the if block.

3. Describe what records are and how they can be used to simplify data carrier classes.

Records in Java 17 are a special kind of class designed to hold immutable data, automatically generating boilerplate code like constructors, getters, equals, hashCode, and toString methods. This simplifies data carrier classes.

Example:

public record Person(String name, int age) {}

The Person record automatically generates necessary methods, reducing boilerplate code. Records are immutable, making them suitable for representing unchangeable data.

4. Write a code snippet demonstrating the use of text blocks for multi-line strings.

Text blocks in Java 17 allow for multi-line string literals, making it easier to work with large text blocks. They are enclosed in triple double-quotes and preserve the text’s formatting.

Example:

public class TextBlockExample {
    public static void main(String[] args) {
        String json = """
                      {
                          "name": "John Doe",
                          "age": 30,
                          "city": "New York"
                      }
                      """;

        System.out.println(json);
    }
}

5. Write a code snippet using switch expressions to handle multiple cases more concisely.

Switch expressions in Java 17 provide a concise way to handle multiple cases. Unlike traditional switch statements, they can return a value and be used in a more functional style.

Example:

public class SwitchExpressionExample {
    public static void main(String[] args) {
        String day = "MONDAY";
        int dayNumber = switch (day) {
            case "MONDAY", "FRIDAY", "SUNDAY" -> 6;
            case "TUESDAY" -> 7;
            case "THURSDAY", "SATURDAY" -> 8;
            case "WEDNESDAY" -> 9;
            default -> throw new IllegalArgumentException("Invalid day: " + day);
        };
        System.out.println("Day number is: " + dayNumber);
    }
}

6. Explain the concept of strong encapsulation by default in the context of the Java module system.

Strong encapsulation by default in the Java module system means a module’s internal implementation details are hidden unless explicitly made accessible. This shift from the traditional Java classpath promotes better modularity and maintainability.

For example, consider a module com.example.myapp with the following module-info.java:

module com.example.myapp {
    exports com.example.myapp.api;
}

Only the com.example.myapp.api package is accessible to other modules. This ensures internal implementation details remain hidden, promoting better modularity and maintainability.

Benefits include improved security by reducing unintended access, enhanced maintainability by allowing internal refactoring without breaking external dependencies, and clearer API boundaries.

7. Write a code snippet implementing one of the new enhanced pseudo-random number generators.

Java 17 introduced new interfaces and classes for enhanced pseudo-random number generation. The RandomGenerator interface and its implementations provide a more flexible framework for random number generation.

Here is a code snippet demonstrating the use of the new RandomGenerator interface:

import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;

public class RandomNumberExample {
    public static void main(String[] args) {
        RandomGenerator generator = RandomGeneratorFactory.of("L64X128MixRandom").create();
        System.out.println("Random number: " + generator.nextInt());
    }
}

In this example, RandomGeneratorFactory creates an instance of L64X128MixRandom, part of the new algorithms introduced in Java 17.

8. Discuss the impact of strongly encapsulating JDK internals by default as per JEP 396.

JEP 396, introduced in Java 17, strongly encapsulates JDK internals by default, hiding internal APIs that were previously accessible. This change aims to improve the security and maintainability of the JDK by preventing unintended dependencies on internal APIs.

The impact is significant for developers relying on these internal APIs, as applications may break, requiring alternative solutions or migration to supported public APIs. This change encourages better coding practices by promoting the use of stable, documented APIs.

Encapsulation enhances security by reducing the attack surface and simplifies JDK maintenance, leading to a more stable Java platform.

9. Explain the further encapsulation efforts described in JEP 403 and their importance.

JEP 403, “Strongly Encapsulate JDK Internals,” aims to restrict access to internal APIs not meant for public use, enhancing the security and maintainability of Java applications.

Encapsulation allows JDK developers to make changes without breaking existing code that relies on internals. It aligns with the modularization introduced in Java 9, promoting a cleaner architecture and encouraging the use of standard APIs for future-proofing.

10. Write a code snippet to implement context-specific deserialization filters as per JEP 415.

Context-specific deserialization filters in Java 17, as introduced by JEP 415, allow developers to define custom filters during the deserialization process, enhancing security by preventing the deserialization of potentially harmful classes.

Here is a concise code snippet demonstrating how to implement context-specific deserialization filters:

import java.io.*;
import java.util.function.Function;
import java.io.ObjectInputFilter.FilterInfo;

public class DeserializationFilterExample {
    public static void main(String[] args) {
        Function<FilterInfo, ObjectInputFilter.Status> filter = info -> {
            if (info.serialClass() != null && info.serialClass().getName().equals("java.util.ArrayList")) {
                return ObjectInputFilter.Status.ALLOWED;
            }
            return ObjectInputFilter.Status.REJECTED;
        };

        ObjectInputFilter.Config.setSerialFilter(filter::apply);

        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data.ser"))) {
            Object obj = ois.readObject();
            System.out.println("Deserialized object: " + obj);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

11. Write a code snippet using the second incubator version of the Vector API to perform a complex vector operation.

import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorSpecies;

public class VectorExample {
    private static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;

    public static void main(String[] args) {
        float[] a = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f};
        float[] b = {8.0f, 7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f};
        float[] result = new float[a.length];

        for (int i = 0; i < a.length; i += SPECIES.length()) {
            var va = FloatVector.fromArray(SPECIES, a, i);
            var vb = FloatVector.fromArray(SPECIES, b, i);
            var vr = va.mul(vb).add(va);
            vr.intoArray(result, i);
        }

        for (float v : result) {
            System.out.println(v);
        }
    }
}

12. Explain how sealed interfaces work and provide an example scenario where they would be beneficial.

Sealed interfaces in Java 17 allow you to define a restricted set of classes or interfaces that can implement or extend them. This feature is useful for maintaining a controlled and predictable class hierarchy.

Example scenario: In a financial application, you might have a Transaction interface that should only be implemented by specific types of transactions like Deposit, Withdrawal, and Transfer. Using a sealed interface ensures that no other types of transactions can be introduced without explicit permission.

public sealed interface Transaction permits Deposit, Withdrawal, Transfer {
    void execute();
}

public final class Deposit implements Transaction {
    @Override
    public void execute() {
        // Implementation for deposit
    }
}

public final class Withdrawal implements Transaction {
    @Override
    public void execute() {
        // Implementation for withdrawal
    }
}

public final class Transfer implements Transaction {
    @Override
    public void execute() {
        // Implementation for transfer
    }
}

In this example, the Transaction interface is sealed, and only the Deposit, Withdrawal, and Transfer classes are permitted to implement it.

13. Write a code snippet using the Vector API to perform a simple vector computation.

Java 17 introduced the Vector API to leverage SIMD operations for better performance. Below is a simple example that demonstrates how to use the Vector API to add two vectors.

import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorSpecies;

public class VectorExample {
    private static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;

    public static void main(String[] args) {
        float[] a = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f};
        float[] b = {8.0f, 7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f};
        float[] c = new float[a.length];

        for (int i = 0; i < a.length; i += SPECIES.length()) {
            var va = FloatVector.fromArray(SPECIES, a, i);
            var vb = FloatVector.fromArray(SPECIES, b, i);
            var vc = va.add(vb);
            vc.intoArray(c, i);
        }

        for (float value : c) {
            System.out.print(value + " ");
        }
    }
}

14. Write a code snippet to demonstrate the use of the new pseudo-random number generator interfaces.

Java 17 introduced new interfaces and implementations for pseudo-random number generators (PRNGs) to provide more flexibility and better performance. The new interfaces include RandomGenerator and its subinterfaces like SplittableRandomGenerator and JumpableRandomGenerator.

Here is a code snippet demonstrating the use of the new RandomGenerator interface:

import java.util.random.RandomGenerator;
import java.util.random.RandomGeneratorFactory;

public class PRNGExample {
    public static void main(String[] args) {
        RandomGenerator generator = RandomGeneratorFactory.of("L64X128MixRandom").create();
        
        // Generate a random integer
        int randomInt = generator.nextInt();
        System.out.println("Random Integer: " + randomInt);
        
        // Generate a random double
        double randomDouble = generator.nextDouble();
        System.out.println("Random Double: " + randomDouble);
        
        // Generate a random long
        long randomLong = generator.nextLong();
        System.out.println("Random Long: " + randomLong);
    }
}

In this example, we use the RandomGeneratorFactory to create an instance of a specific PRNG algorithm, L64X128MixRandom.

15. Explain the significance of context-specific deserialization filters introduced in Java 17.

Context-specific deserialization filters in Java 17 provide a mechanism to enhance security by allowing developers to define custom filters during the deserialization process. This feature addresses the risk of deserialization vulnerabilities, which can be exploited to execute arbitrary code or cause denial-of-service attacks.

The significance of context-specific deserialization filters lies in their ability to:

  • Improve security: By allowing developers to specify which classes are allowed or disallowed during deserialization, these filters help prevent malicious data from being deserialized.
  • Enhance flexibility: Developers can create filters tailored to specific application contexts, ensuring that only the necessary and safe classes are deserialized.
  • Provide better control: Filters can be applied at different levels, such as globally, per stream, or per object, giving developers fine-grained control over the deserialization process.
Previous

10 Oracle ESB Interview Questions and Answers

Back to Interview
Next

15 Mobile App Testing Interview Questions and Answers