15 Java 17 Interview Questions and Answers
Prepare for your Java 17 interview with curated questions and answers, covering new features and practical applications.
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.
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.
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.
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.
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); } }
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); } }
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.
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.
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.
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.
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(); } } }
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); } } }
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.
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 + " "); } } }
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
.
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: