Introduction
Java 22, released in March 2024, introduces several preview features, incubator APIs, and final features that enhance the language's capabilities. This comprehensive overview covers all the major features with detailed examples and practical use cases.
1. Structured Concurrency (Second Preview - JEP 462)
Structured Concurrency simplifies concurrent programming by treating groups of related tasks as single units of work.
Core Implementation
import java.util.concurrent.*;
import jdk.incubator.concurrent.*;
public class StructuredConcurrencyDemo {
public static void main(String[] args) throws Exception {
var demo = new StructuredConcurrencyDemo();
// Example 1: Basic structured concurrency
demo.basicStructuredTask();
// Example 2: Error handling in structured concurrency
demo.structuredConcurrencyWithErrorHandling();
// Example 3: Shutdown behavior
demo.structuredConcurrencyShutdown();
}
public void basicStructuredTask() throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
// Fork multiple subtasks
Supplier<String> userTask = scope.fork(() -> fetchUserData("user123"));
Supplier<String> productTask = scope.fork(() -> fetchProductData("prod456"));
Supplier<Integer> inventoryTask = scope.fork(() -> checkInventory("prod456"));
// Join all tasks - this waits for all to complete or any to fail
scope.join();
scope.throwIfFailed(); // Throws if any subtask failed
// Combine results
String user = userTask.get();
String product = productTask.get();
int inventory = inventoryTask.get();
System.out.printf("User: %s, Product: %s, Inventory: %d%n",
user, product, inventory);
}
}
public void structuredConcurrencyWithErrorHandling() {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Supplier<String> successTask = scope.fork(() -> successfulTask());
Supplier<String> failingTask = scope.fork(() -> failingTask());
scope.join();
try {
scope.throwIfFailed();
System.out.println("All tasks completed successfully");
} catch (ExecutionException e) {
System.out.println("Task failed with: " + e.getCause().getMessage());
// Handle partial results
if (successTask.state() == Future.State.SUCCESS) {
System.out.println("Successful task result: " + successTask.get());
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Operation interrupted");
}
}
public void structuredConcurrencyShutdown() throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Supplier<String> quickTask = scope.fork(() -> quickOperation());
Supplier<String> slowTask = scope.fork(() -> slowOperation());
// Simulate cancellation after timeout
Thread.sleep(100);
scope.shutdown(); // Cancels all unfinished tasks
scope.join();
if (quickTask.state() == Future.State.SUCCESS) {
System.out.println("Quick task completed: " + quickTask.get());
}
if (slowTask.state() == Future.State.CANCELLED) {
System.out.println("Slow task was cancelled");
}
}
}
// Simulated service methods
private String fetchUserData(String userId) throws InterruptedException {
Thread.sleep(200);
return "User: " + userId;
}
private String fetchProductData(String productId) throws InterruptedException {
Thread.sleep(150);
return "Product: " + productId;
}
private int checkInventory(String productId) throws InterruptedException {
Thread.sleep(100);
return 42;
}
private String successfulTask() throws InterruptedException {
Thread.sleep(50);
return "Success";
}
private String failingTask() throws InterruptedException {
Thread.sleep(50);
throw new RuntimeException("Task failed intentionally");
}
private String quickOperation() throws InterruptedException {
Thread.sleep(50);
return "Quick result";
}
private String slowOperation() throws InterruptedException {
Thread.sleep(1000); // This will be interrupted
return "Slow result";
}
}
Advanced Structured Concurrency Patterns
import java.util.*;
import java.util.concurrent.*;
import jdk.incubator.concurrent.*;
public class AdvancedStructuredConcurrency {
// Custom result collector scope
public static class CollectingScope<T> extends StructuredTaskScope<T> {
private final List<Supplier<T>> completedTasks = new ArrayList<>();
private final List<Throwable> exceptions = new ArrayList<>();
@Override
protected void handleComplete(Future<T> future) {
switch (future.state()) {
case SUCCESS -> completedTasks.add(future);
case FAILED -> exceptions.add(future.exception());
case CANCELLED -> {} // Ignore cancelled tasks
}
}
public List<T> getResults() {
return completedTasks.stream()
.map(Supplier::get)
.toList();
}
public List<Throwable> getExceptions() {
return Collections.unmodifiableList(exceptions);
}
}
public void collectingScopeDemo() throws Exception {
try (var scope = new CollectingScope<String>()) {
// Fork multiple tasks with different outcomes
scope.fork(() -> taskThatSucceeds("Task1"));
scope.fork(() -> taskThatFails("Task2"));
scope.fork(() -> taskThatSucceeds("Task3"));
scope.join();
System.out.println("Successful results: " + scope.getResults());
System.out.println("Exceptions: " +
scope.getExceptions().stream()
.map(Throwable::getMessage)
.toList());
}
}
// Batch processing with structured concurrency
public <T, R> List<R> processBatch(
List<T> items,
Function<T, R> processor,
int maxConcurrency) throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
// Limit concurrency
var futures = items.stream()
.limit(maxConcurrency)
.map(item -> scope.fork(() -> processor.apply(item)))
.toList();
scope.join();
scope.throwIfFailed();
return futures.stream()
.map(Supplier::get)
.toList();
}
}
// Race between multiple services
public String raceMultipleServices(List<Callable<String>> services) throws Exception {
try (var scope = new StructuredTaskScope<String>()) {
var futures = services.stream()
.map(service -> scope.fork(service::call))
.toList();
scope.join();
// Return the first successful result
return futures.stream()
.filter(future -> future.state() == Future.State.SUCCESS)
.findFirst()
.map(Supplier::get)
.orElseThrow(() -> new RuntimeException("All services failed"));
}
}
private String taskThatSucceeds(String name) {
return name + "-success";
}
private String taskThatFails(String name) {
throw new RuntimeException(name + "-failed");
}
}
2. Scoped Values (Second Preview - JEP 464)
Scoped Values provide a way to share immutable data within and across threads, replacing ThreadLocal for many use cases.
Basic Usage
import jdk.incubator.concurrent.*;
public class ScopedValuesDemo {
// Define scoped values
private static final ScopedValue<String> CURRENT_USER = ScopedValue.newInstance();
private static final ScopedValue<Locale> USER_LOCALE = ScopedValue.newInstance();
private static final ScopedValue<Map<String, String>> REQUEST_CONTEXT = ScopedValue.newInstance();
public static void main(String[] args) throws Exception {
var demo = new ScopedValuesDemo();
// Example 1: Basic scoped value usage
demo.basicScopedValue();
// Example 2: Nested scopes
demo.nestedScopes();
// Example 3: With structured concurrency
demo.scopedValuesWithConcurrency();
// Example 4: Request context simulation
demo.requestContextExample();
}
public void basicScopedValue() {
// Bind value for the scope
ScopedValue.where(CURRENT_USER, "alice")
.run(() -> {
System.out.println("Current user: " + CURRENT_USER.get());
processUserRequest();
});
// Outside the scope, the value is unbound
try {
System.out.println(CURRENT_USER.get());
} catch (IllegalStateException e) {
System.out.println("Correctly caught: " + e.getMessage());
}
}
public void nestedScopes() {
ScopedValue.where(CURRENT_USER, "bob")
.run(() -> {
System.out.println("Outer scope user: " + CURRENT_USER.get());
// Nested scope with different value
ScopedValue.where(CURRENT_USER, "charlie")
.run(() -> {
System.out.println("Inner scope user: " + CURRENT_USER.get());
});
// Back to original value
System.out.println("Back to outer scope user: " + CURRENT_USER.get());
});
}
public void scopedValuesWithConcurrency() throws Exception {
ScopedValue.where(CURRENT_USER, "main-thread-user")
.where(USER_LOCALE, Locale.US)
.run(() -> {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
// Fork tasks that inherit scoped values
var task1 = scope.fork(() -> {
System.out.println("Task 1 user: " + CURRENT_USER.get());
System.out.println("Task 1 locale: " + USER_LOCALE.get());
return "task1-result";
});
var task2 = scope.fork(() -> {
System.out.println("Task 2 user: " + CURRENT_USER.get());
System.out.println("Task 2 locale: " + USER_LOCALE.get());
return "task2-result";
});
scope.join();
scope.throwIfFailed();
System.out.println("Results: " + task1.get() + ", " + task2.get());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
public void requestContextExample() {
Map<String, String> context = Map.of(
"requestId", "req-12345",
"sessionId", "sess-67890",
"userAgent", "Mozilla/5.0"
);
ScopedValue.where(REQUEST_CONTEXT, context)
.where(CURRENT_USER, "api-user")
.run(() -> {
handleApiRequest();
performDatabaseOperation();
logAuditEvent();
});
}
private void processUserRequest() {
System.out.println("Processing request for: " + CURRENT_USER.get());
// Access scoped value in called methods
validateUser();
checkPermissions();
}
private void validateUser() {
String user = CURRENT_USER.get();
System.out.println("Validating user: " + user);
}
private void checkPermissions() {
String user = CURRENT_USER.get();
System.out.println("Checking permissions for: " + user);
}
private void handleApiRequest() {
Map<String, String> context = REQUEST_CONTEXT.get();
String user = CURRENT_USER.get();
System.out.printf("Handling API request - User: %s, RequestId: %s%n",
user, context.get("requestId"));
}
private void performDatabaseOperation() {
Map<String, String> context = REQUEST_CONTEXT.get();
System.out.println("DB operation for request: " + context.get("requestId"));
}
private void logAuditEvent() {
Map<String, String> context = REQUEST_CONTEXT.get();
String user = CURRENT_USER.get();
System.out.printf("Audit event - User: %s, Session: %s%n",
user, context.get("sessionId"));
}
}
Advanced Scoped Values Patterns
import jdk.incubator.concurrent.*;
import java.util.*;
import java.util.concurrent.*;
public class AdvancedScopedValues {
private static final ScopedValue<Transaction> CURRENT_TRANSACTION = ScopedValue.newInstance();
private static final ScopedValue<SecurityContext> SECURITY_CONTEXT = ScopedValue.newInstance();
private static final ScopedValue<Map<String, Object>> FEATURE_FLAGS = ScopedValue.newInstance();
// Transaction management with scoped values
public static class Transaction {
private final String id;
private final List<String> operations = new ArrayList<>();
private boolean committed = false;
public Transaction(String id) {
this.id = id;
}
public void addOperation(String operation) {
operations.add(operation);
}
public void commit() {
this.committed = true;
System.out.println("Transaction " + id + " committed with operations: " + operations);
}
public void rollback() {
System.out.println("Transaction " + id + " rolled back");
}
}
public static class SecurityContext {
private final String userId;
private final Set<String> roles;
private final String tenantId;
public SecurityContext(String userId, Set<String> roles, String tenantId) {
this.userId = userId;
this.roles = Set.copyOf(roles);
this.tenantId = tenantId;
}
public boolean hasRole(String role) {
return roles.contains(role);
}
public String getUserId() { return userId; }
public Set<String> getRoles() { return roles; }
public String getTenantId() { return tenantId; }
}
public void transactionExample() {
Transaction tx = new Transaction("tx-" + System.currentTimeMillis());
ScopedValue.where(CURRENT_TRANSACTION, tx)
.run(() -> {
try {
performBusinessOperation();
tx.commit();
} catch (Exception e) {
tx.rollback();
throw e;
}
});
}
public void securityContextExample() {
SecurityContext securityContext = new SecurityContext(
"user123",
Set.of("ADMIN", "USER"),
"tenant-abc"
);
ScopedValue.where(SECURITY_CONTEXT, securityContext)
.run(() -> {
accessSecureResource();
performAdminOperation();
});
}
public void featureFlagsExample() {
Map<String, Object> flags = Map.of(
"new_ui_enabled", true,
"experimental_feature", false,
"max_records", 1000
);
ScopedValue.where(FEATURE_FLAGS, flags)
.run(() -> {
renderUI();
processData();
});
}
// Method that requires transaction context
private void performBusinessOperation() {
Transaction tx = CURRENT_TRANSACTION.get();
tx.addOperation("update_user_profile");
tx.addOperation("send_notification");
System.out.println("Performing business operation in transaction: " + tx.id);
}
// Method that requires security context
private void accessSecureResource() {
SecurityContext context = SECURITY_CONTEXT.get();
if (!context.hasRole("USER")) {
throw new SecurityException("Access denied");
}
System.out.println("Accessing secure resource for user: " + context.getUserId());
}
private void performAdminOperation() {
SecurityContext context = SECURITY_CONTEXT.get();
if (!context.hasRole("ADMIN")) {
throw new SecurityException("Admin access required");
}
System.out.println("Performing admin operation");
}
private void renderUI() {
Map<String, Object> flags = FEATURE_FLAGS.get();
boolean newUIEnabled = (Boolean) flags.get("new_ui_enabled");
if (newUIEnabled) {
System.out.println("Rendering new UI");
} else {
System.out.println("Rendering legacy UI");
}
}
private void processData() {
Map<String, Object> flags = FEATURE_FLAGS.get();
int maxRecords = (Integer) flags.get("max_records");
System.out.println("Processing data with max records: " + maxRecords);
}
// Cross-thread scoped value propagation
public void crossThreadScopedValues() throws Exception {
ScopedValue.where(CURRENT_USER, "parent-thread-user")
.run(() -> {
try (var scope = new StructuredTaskScope<String>()) {
// Child threads inherit scoped values
var task1 = scope.fork(() -> {
String user = CURRENT_USER.get();
return "Task completed for user: " + user;
});
var task2 = scope.fork(() -> {
String user = CURRENT_USER.get();
return "Another task for user: " + user;
});
scope.join();
System.out.println(task1.get());
System.out.println(task2.get());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
}
3. String Templates (Second Preview - JEP 459)
String Templates provide a safer, more efficient way to compose strings than traditional concatenation or StringBuilder.
Basic String Templates
public class StringTemplatesDemo {
public static void main(String[] args) {
var demo = new StringTemplatesDemo();
// Example 1: Basic string templates
demo.basicTemplates();
// Example 2: Expression templates
demo.expressionTemplates();
// Example 3: Multiline templates
demo.multilineTemplates();
// Example 4: Custom template processors
demo.customTemplateProcessors();
// Example 5: SQL and HTML templates
demo.safeTemplates();
}
public void basicTemplates() {
String name = "Alice";
int age = 30;
// Basic string template
String message = STR."Hello, my name is \{name} and I'm \{age} years old";
System.out.println(message);
// Complex expressions in templates
String complex = STR."""
Calculation result:
- Name: \{name}
- Age: \{age}
- Next year: \{age + 1}
- Length of name: \{name.length()}
""";
System.out.println(complex);
}
public void expressionTemplates() {
// Mathematical expressions
int x = 10, y = 20;
String math = STR."\{x} + \{y} = \{x + y}";
System.out.println(math);
// Method calls in templates
List<String> items = List.of("apple", "banana", "cherry");
String listInfo = STR."""
List information:
- Size: \{items.size()}
- First item: \{items.getFirst()}
- Contains 'banana': \{items.contains("banana")}
""";
System.out.println(listInfo);
// Conditional expressions
int score = 85;
String grade = STR."Score: \{score}, Grade: \{(score >= 90) ? "A" : (score >= 80) ? "B" : "C"}";
System.out.println(grade);
}
public void multilineTemplates() {
String className = "UserService";
String methodName = "getUser";
List<String> parameters = List.of("userId", "includeProfile");
// Generate code with multiline templates
String code = STR."""
public class \{className} {
public User \{methodName}(String userId, boolean includeProfile) {
// Implementation here
return userRepository.findById(userId)
.map(user -> {
if (includeProfile) {
user.loadProfile();
}
return user;
});
}
}
""";
System.out.println(code);
// JSON generation
String json = STR."""
{
"user": {
"name": "John Doe",
"email": "[email protected]",
"active": true,
"roles": ["USER", "EDITOR"]
}
}
""";
System.out.println(json);
}
public void customTemplateProcessors() {
// FMT processor for formatting
String formatted = FMT."""
Formatted values:
- Percentage: %.2f\{0.8567}
- Currency: $%,.2f\{1234.56}
- Padded number: %05d\{42}
""";
System.out.println(formatted);
// Custom processor for validation
StringTemplate.Processor<String, RuntimeException> validator =
StringTemplate.Processor.of((StringTemplate st) -> {
for (Object value : st.values()) {
if (value instanceof String str && str.contains("'")) {
throw new IllegalArgumentException("Invalid character in string: " + str);
}
}
return st.interpolate();
});
try {
String safe = validator."Safe string: \{"normal text"}";
System.out.println(safe);
// This will throw an exception
validator."Unsafe string: \{"text with ' quote"}";
} catch (IllegalArgumentException e) {
System.out.println("Caught expected exception: " + e.getMessage());
}
}
public void safeTemplates() {
// SQL template with custom processor
StringTemplate.Processor<PreparedStatement, SQLException> SQL =
StringTemplate.Processor.of((StringTemplate st) -> {
String query = String.join("?", st.fragments());
PreparedStatement ps = createPreparedStatement(query);
for (int i = 0; i < st.values().size(); i++) {
ps.setObject(i + 1, st.values().get(i));
}
return ps;
});
// HTML template with escaping
StringTemplate.Processor<String, RuntimeException> HTML =
StringTemplate.Processor.of((StringTemplate st) -> {
StringBuilder sb = new StringBuilder();
List<String> fragments = st.fragments();
List<Object> values = st.values();
for (int i = 0; i < fragments.size(); i++) {
sb.append(fragments.get(i));
if (i < values.size()) {
String escaped = escapeHtml(values.get(i).toString());
sb.append(escaped);
}
}
return sb.toString();
});
try {
String userInput = "<script>alert('xss')</script>";
String safeHtml = HTML."""
<div class="user-content">
\{userInput}
</div>
""";
System.out.println("Safe HTML: " + safeHtml);
} catch (Exception e) {
System.out.println("HTML processing error: " + e.getMessage());
}
}
private String escapeHtml(String input) {
return input.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace("\"", """)
.replace("'", "'");
}
private PreparedStatement createPreparedStatement(String query) throws SQLException {
// Mock implementation
System.out.println("Creating prepared statement: " + query);
return null;
}
}
Advanced String Template Processors
import java.util.*;
import java.time.*;
import java.util.regex.*;
public class AdvancedStringTemplates {
// JSON template processor
public static final StringTemplate.Processor<JSONObject, RuntimeException> JSON =
StringTemplate.Processor.of((StringTemplate st) -> {
JSONObject json = new JSONObject();
List<String> fragments = st.fragments();
List<Object> values = st.values();
// Simple key-value parsing (for demonstration)
for (int i = 0; i < fragments.size(); i++) {
String fragment = fragments.get(i);
// Extract key from fragment (simplified)
String key = extractJsonKey(fragment);
if (key != null && i < values.size()) {
json.put(key, values.get(i));
}
}
return json;
});
// Logging template processor
public static final StringTemplate.Processor<Void, RuntimeException> LOG =
StringTemplate.Processor.of((StringTemplate st) -> {
String message = st.interpolate();
System.out.println(LocalDateTime.now() + " [INFO] " + message);
return null;
});
// Validation template processor
public static final StringTemplate.Processor<String, IllegalArgumentException> VALIDATED =
StringTemplate.Processor.of((StringTemplate st) -> {
for (Object value : st.values()) {
if (value == null) {
throw new IllegalArgumentException("Null values not allowed");
}
if (value instanceof String str && str.isBlank()) {
throw new IllegalArgumentException("Empty strings not allowed");
}
}
return st.interpolate();
});
// Localization template processor
public static class LocalizedProcessor implements StringTemplate.Processor<String, RuntimeException> {
private final ResourceBundle bundle;
public LocalizedProcessor(Locale locale) {
this.bundle = ResourceBundle.getBundle("messages", locale);
}
@Override
public String process(StringTemplate st) {
StringBuilder result = new StringBuilder();
List<String> fragments = st.fragments();
List<Object> values = st.values();
for (int i = 0; i < fragments.size(); i++) {
String fragment = fragments.get(i);
// Look up translation
String translated = bundle.getString(fragment.trim());
result.append(translated);
if (i < values.size()) {
result.append(values.get(i));
}
}
return result.toString();
}
}
public static void main(String[] args) {
var demo = new AdvancedStringTemplates();
demo.jsonTemplates();
demo.loggingTemplates();
demo.validationTemplates();
demo.localizationTemplates();
}
public void jsonTemplates() {
String name = "John Doe";
int age = 30;
boolean active = true;
JSONObject userJson = JSON."""
{
"name": "\{name}",
"age": \{age},
"active": \{active},
"createdAt": "\{LocalDateTime.now()}"
}
""";
System.out.println("Generated JSON: " + userJson);
}
public void loggingTemplates() {
String userId = "user123";
String action = "login";
int duration = 150;
LOG."User \{userId} performed action \{action} in \{duration}ms";
LOG."System health check - Memory: \{Runtime.getRuntime().freeMemory()} free";
}
public void validationTemplates() {
String validName = "Alice";
String emptyName = "";
try {
String valid = VALIDATED."Hello, \{validName}!";
System.out.println("Valid: " + valid);
String invalid = VALIDATED."Hello, \{emptyName}!";
} catch (IllegalArgumentException e) {
System.out.println("Caught validation error: " + e.getMessage());
}
}
public void localizationTemplates() {
LocalizedProcessor english = new LocalizedProcessor(Locale.ENGLISH);
LocalizedProcessor french = new LocalizedProcessor(Locale.FRENCH);
String name = "Pierre";
int count = 3;
String englishMessage = english."greeting" + name + "welcome" + count + "messages";
String frenchMessage = french."greeting" + name + "welcome" + count + "messages";
System.out.println("English: " + englishMessage);
System.out.println("French: " + frenchMessage);
}
private static String extractJsonKey(String fragment) {
// Simplified key extraction - in real implementation, use proper parsing
Pattern pattern = Pattern.compile("\"([^\"]+)\"\\s*:");
Matcher matcher = pattern.matcher(fragment);
return matcher.find() ? matcher.group(1) : null;
}
// Mock JSONObject class for demonstration
static class JSONObject {
private final Map<String, Object> map = new HashMap<>();
public void put(String key, Object value) {
map.put(key, value);
}
@Override
public String toString() {
return map.toString();
}
}
}
4. Implicitly Declared Classes and Instance Main Methods (Second Preview - JEP 463)
This feature simplifies Java for beginners by allowing more flexible class and method declarations.
Simplified Java Syntax
// Simple standalone file - HelloWorld.java
void main() {
System.out.println("Hello, World!");
}
// With parameters
void main(String[] args) {
if (args.length > 0) {
System.out.println("Hello, " + args[0] + "!");
} else {
System.out.println("Hello, World!");
}
}
// With class fields and methods
String message = "Welcome to Java!";
void main() {
printMessage();
calculateSum(5, 3);
}
void printMessage() {
System.out.println(message);
}
void calculateSum(int a, int b) {
System.out.println(a + " + " + b + " = " + (a + b));
}
Advanced Examples
// Student Management System in simplified syntax
import java.util.*;
import java.time.*;
// Implicit class with instance main
List<Student> students = new ArrayList<>();
void main() {
setupSampleData();
displayMenu();
}
void setupSampleData() {
students.add(new Student("Alice", "Johnson", LocalDate.of(2000, 5, 15), "Computer Science"));
students.add(new Student("Bob", "Smith", LocalDate.of(1999, 8, 22), "Mathematics"));
students.add(new Student("Carol", "Davis", LocalDate.of(2001, 3, 8), "Physics"));
}
void displayMenu() {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("\n=== Student Management System ===");
System.out.println("1. List all students");
System.out.println("2. Add new student");
System.out.println("3. Find student by name");
System.out.println("4. Exit");
System.out.print("Choose an option: ");
String choice = scanner.nextLine();
switch (choice) {
case "1" -> listStudents();
case "2" -> addStudent(scanner);
case "3" -> findStudent(scanner);
case "4" -> {
System.out.println("Goodbye!");
return;
}
default -> System.out.println("Invalid option!");
}
}
}
void listStudents() {
System.out.println("\n=== All Students ===");
for (int i = 0; i < students.size(); i++) {
Student student = students.get(i);
System.out.printf("%d. %s %s (%s) - %s%n",
i + 1, student.firstName(), student.lastName(),
student.birthDate(), student.major());
}
}
void addStudent(Scanner scanner) {
System.out.println("\n=== Add New Student ===");
System.out.print("First name: ");
String firstName = scanner.nextLine();
System.out.print("Last name: ");
String lastName = scanner.nextLine();
System.out.print("Birth date (YYYY-MM-DD): ");
LocalDate birthDate = LocalDate.parse(scanner.nextLine());
System.out.print("Major: ");
String major = scanner.nextLine();
students.add(new Student(firstName, lastName, birthDate, major));
System.out.println("Student added successfully!");
}
void findStudent(Scanner scanner) {
System.out.print("Enter name to search: ");
String searchName = scanner.nextLine().toLowerCase();
List<Student> found = students.stream()
.filter(s -> s.firstName().toLowerCase().contains(searchName) ||
s.lastName().toLowerCase().contains(searchName))
.toList();
if (found.isEmpty()) {
System.out.println("No students found with that name.");
} else {
System.out.println("\n=== Found Students ===");
found.forEach(s -> System.out.printf("- %s %s (%s)%n",
s.firstName(), s.lastName(), s.major()));
}
}
// Record for student data
record Student(String firstName, String lastName, LocalDate birthDate, String major) {
public int getAge() {
return Period.between(birthDate, LocalDate.now()).getYears();
}
}
5. Vector API (Seventh Incubator - JEP 460)
The Vector API provides expressive and reliable vector computations that compile to optimal vector hardware instructions.
Basic Vector Operations
```java
import jdk.incubator.vector.*;
public class VectorAPIDemo {
public static void main(String[] args) {
var demo = new VectorAPIDemo();
demo.basicVectorOperations();
demo.vectorizedComputation();
demo.performanceComparison();
}
public void basicVectorOperations() {
// Define vector species (type and size)
VectorSpecies<Float> species = FloatVector.SPECIES_PREFERRED;
System.out.println("Preferred float vector size: " + species.length());
// Create vectors
float[] arrayA = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f};
float[] arrayB = {2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f};
FloatVector vectorA = FloatVector.fromArray(species, arrayA, 0);
FloatVector vectorB = FloatVector.fromArray(species, arrayB, 0);
// Vector operations
FloatVector sum = vectorA.add(vectorB);
FloatVector product = vectorA.mul(vectorB);
FloatVector combined = vectorA.fma(vectorB, sum); // Fused multiply-add
// Store results
float[] result = new float[arrayA.length];
sum.intoArray(result, 0);
System.out.println("Vector A: " + vectorA);
System.out.println("Vector B: " + vectorB);
System.out.println("Sum: " + sum);
System.out.println("Product: " + product);
System.out.println("FMA: " + combined);
}
public void vectorizedComputation() {
int size = 1024;
float[] a = new float[size];
float[] b = new float[size];
float[] c = new float[size];
// Initialize arrays
for (int i = 0; i < size; i++) {
a[i] = i * 0.1f;
b[i] = i * 0.2f;
}
VectorSpecies<Float> species = FloatVector.SPECIES_PREFERRED;
// Vectorized array addition
for (int i = 0; i < size; i += species.length()) {
VectorMask<Float> mask = species.indexInRange(i, size);
FloatVector va = FloatVector.fromArray(species, a, i, mask);
FloatVector vb = FloatVector.fromArray(species, b, i, mask);
FloatVector vc = va.add(vb);
vc.intoArray(c, i, mask);
}
// Verify results
System.out.println("Vectorized computation completed");
System.out.println("Sample result: c[10] = " + c[10]);
}
public void performanceComparison() {
int size = 1000000;
float[] array1 = new float[size];
float[] array2 = new float[size];
float[] resultScalar = new float[size];
float[] resultVector = new float[size];
// Initialize arrays with random data
for (int i = 0; i < size; i++) {
array1[i] = (float) Math.random();
array2[i] = (float) Math.random();
}
// Scalar implementation
long scalarStart = System.nanoTime();
for (int i = 0; i < size; i++) {
resultScalar[i] = array1[i] + array2[i];
}
long scalarTime = System.nanoTime() - scalarStart;
// Vector implementation
long vectorStart = System.nanoTime();
vectorizedAdd(array1, array2, resultVector);
long vectorTime = System.nanoTime() - vectorStart;
System.out.printf("Scalar time: %,d ns%n", scalarTime