Skip to main content
Java

Java 12: Switch Expressions and Preview Features

Ravinder··5 min read
JavaSwitch ExpressionsPattern MatchingJava 12
Share:
Java 12: Switch Expressions and Preview Features

Java 12: Switch Expressions and Language Preview

Java 12 (March 2019) introduced preview features, most notably switch expressions. It also enhanced performance and added new APIs. Java 12 was not LTS, but its features paved the way for future releases.

1. Switch Expressions (Preview)

Switch expressions provide a more concise and safer alternative to traditional switch statements.

Before Java 12:

// Traditional switch statement
int daysInMonth;
switch (month) {
    case JANUARY:
    case MARCH:
    case MAY:
    case JULY:
    case AUGUST:
    case DECEMBER:
        daysInMonth = 31;
        break;
    case APRIL:
    case JUNE:
    case SEPTEMBER:
    case NOVEMBER:
        daysInMonth = 30;
        break;
    case FEBRUARY:
        daysInMonth = 28;
        break;
    default:
        throw new IllegalArgumentException("Invalid month");
}
 
// Risk of forgetting break statement
// daysInMonth could be uninitialized

After Java 12:

// Switch expression - cleaner and safer
int daysInMonth = switch (month) {
    case JANUARY, MARCH, MAY, JULY, AUGUST, DECEMBER -> 31;
    case APRIL, JUNE, SEPTEMBER, NOVEMBER -> 30;
    case FEBRUARY -> 28;
};
 
// No need for break, no fall-through risk
// Expression must return a value for all cases

Advanced Switch Expression:

// Multi-line case blocks
String status = switch (orderStatus) {
    case PENDING -> {
        notifyWarehouse();
        yield "Processing";
    }
    case SHIPPED -> {
        trackPackage();
        yield "On the way";
    }
    case DELIVERED -> "Completed";
    case CANCELLED -> throw new CancelledException();
};
 
// Using yield for complex logic
int discount = switch (customerTier) {
    case BRONZE -> {
        log("Bronze customer discount: 5%");
        yield 5;
    }
    case SILVER -> {
        log("Silver customer discount: 10%");
        yield 10;
    }
    case GOLD -> {
        log("Gold customer discount: 15%");
        yield 15;
    }
};

2. Text Blocks (Preview)

Multi-line strings without escaping newlines.

Before Java 12:

// Verbose and hard to read
String json = "{\n" +
    "  \"name\": \"John\",\n" +
    "  \"age\": 30,\n" +
    "  \"email\": \"john@example.com\"\n" +
}";
 
String html = "<div>\n" +
    "  <h1>Hello</h1>\n" +
    "  <p>Welcome</p>\n" +
    "</div>";
 
String sql = "SELECT id, name, email " +
    "FROM users " +
    "WHERE age > ? " +
    "AND status = ?";

After Java 13 (Text Blocks became feature):

// Clean and readable
String json = """
    {
      "name": "John",
      "age": 30,
      "email": "john@example.com"
    }
    """;
 
String html = """
    <div>
      <h1>Hello</h1>
      <p>Welcome</p>
    </div>
    """;
 
String sql = """
    SELECT id, name, email
    FROM users
    WHERE age > ?
    AND status = ?
    """;
 
// With escapes if needed
String withTab = """
    Column1\tColumn2\tColumn3
    Value1\tValue2\tValue3
    """;

3. Compact Number Formatting

Format numbers in a compact way.

import java.text.NumberFormat;
import java.util.Locale;
 
NumberFormat formatter = NumberFormat.getCompactNumberInstance();
 
System.out.println(formatter.format(1000));      // 1K
System.out.println(formatter.format(1000000));   // 1M
System.out.println(formatter.format(1000000000)); // 1B
 
// Short format
NumberFormat shortFormat = NumberFormat
    .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
System.out.println(shortFormat.format(1234567)); // 1M
 
// Long format
NumberFormat longFormat = NumberFormat
    .getCompactNumberInstance(Locale.US, NumberFormat.Style.LONG);
System.out.println(longFormat.format(1234567)); // 1 million

4. Stream API Enhancements

New utility methods for stream processing.

// teeing(): Combine two collectors
import java.util.stream.Collectors;
 
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
 
// Old way: Two separate passes
int sum = numbers.stream().mapToInt(Integer::intValue).sum();
long count = numbers.stream().count();
 
// New way: Single pass
var result = numbers.stream()
    .collect(Collectors.teeing(
        Collectors.summingInt(Integer::intValue),
        Collectors.counting(),
        (sum, count) -> new AbstractMap.SimpleEntry<>(sum, count)
    ));
 
System.out.println("Sum: " + result.getKey());    // 15
System.out.println("Count: " + result.getValue()); // 5

5. String Methods

New methods for string operations.

// indent(): Add indentation
String code = "for (int i = 0; i < 10; i++) {\n  count++;\n}";
String indented = code.indent(4);
 
// transform(): Apply function to string
String email = "john@example.com";
String validated = email.transform(str -> 
    str.matches("[a-zA-Z0-9+_.-]+@[a-zA-Z0-9.-]+") 
        ? str 
        : null
);
 
// describeConstable(): Get constant pool entry
Optional<String> constant = "Hello".describeConstable();

6. File Handling Improvements

Enhanced file I/O methods.

import java.nio.file.Files;
import java.nio.file.Path;
 
Path file = Path.of("example.txt");
 
// copyFile with options
Files.copy(file, Path.of("backup.txt"), 
    StandardCopyOption.REPLACE_EXISTING);
 
// mismatch(): Find first position where files differ (Java 12)
long mismatchPosition = Files.mismatch(
    Path.of("file1.txt"),
    Path.of("file2.txt")
);
if (mismatchPosition == -1) {
    System.out.println("Files are identical");
} else {
    System.out.println("First difference at byte: " + mismatchPosition);
}

Developer Impact

Positive:

  • Switch Expressions: Cleaner, safer switch statements
  • Text Blocks: Much easier to read multi-line strings
  • Number Formatting: Human-readable number display
  • Stream Enhancements: More flexible stream operations

Learning Curve:

  • Switch expressions require mindset shift
  • Preview features need explicit compiler flags
  • Syntax is different from traditional switches

Pros and Cons

Pros ✅

  • Switch Expressions: Eliminates fall-through bugs
  • Text Blocks: Dramatically improves readability
  • Concise Code: Less boilerplate for common patterns
  • Type Safety: Expression must return value for all cases
  • Compact Numbers: Better UX for large numbers
  • **Stream teeing(): Single-pass multiple operations

Cons ❌

  • Preview Status: Features liable to change
  • Learning Curve: Different from traditional switch
  • Not LTS: Short support window (3 months)
  • Breaking Changes: Preview features may be removed
  • Compilation: Need explicit flags for preview features

Compilation with Preview Features

# Enable preview features
javac --enable-preview --release 12 MyClass.java
 
# Run with preview features
java --enable-preview MyClass

Real-World Example

public class OrderProcessor {
    enum OrderStatus { PENDING, PROCESSING, SHIPPED, DELIVERED, CANCELLED }
    
    public String getOrderMessage(OrderStatus status) {
        return switch (status) {
            case PENDING -> "Your order is being prepared";
            case PROCESSING -> "Your order is being packed";
            case SHIPPED -> {
                sendTrackingNotification();
                yield "Your order is on the way!";
            }
            case DELIVERED -> "Thank you for your order!";
            case CANCELLED -> throw new OrderCancelledException();
        };
    }
    
    public String formatOrderStats(int orders) {
        NumberFormat formatter = NumberFormat.getCompactNumberInstance();
        return STR."You have \{formatter.format(orders)} orders";
    }
}

Conclusion

Java 12 introduced powerful preview features that modernized Java's syntax. While not LTS, it demonstrated Java's commitment to evolving the language based on developer feedback. The switch expressions and text blocks became standard features in later Java versions and significantly improve code readability.

Key Takeaway:

  • Switch expressions make code safer and more readable
  • Text blocks are invaluable for configuration and queries
  • Preview features allow safe experimentation with new syntax