You are here
Home > java > Core Java >

Java 17 Coding Interview Questions and Solutions

Java 17 Coding Interview Questions and Solutions

Java 17 Coding Interview Questions and SolutionsIn this article we will explore various real world coding problems & their solutions using Java 17 or later versions.

These questions are based on the most significant Java 17 features to help you understand how to use them effectively in real time projects.

For conceptual knowledge of Java 17 new features, kindly refer Java 17 Features with examples.

Table of Contents

Java 17 Coding Interview Questions and Solutions

Problem#1: Identify Leap Years — Using Ternary Conditional Operator in case statement

Write a program that determines whether a year is a leap year or a common year. Use Java 17 features to write your code.

Solution:

public class LeapYearChecker {
    public static String checkYear(Number year) {
        return switch (year) {
            case Integer y -> (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0) ?
                       "Leap Year" : "Common Year";
            default -> "Invalid Year";
        };
    }

    public static void main(String[] args) {
        System.out.println(checkYear(2000)); 
        System.out.println(checkYear(1900)); 
        System.out.println(checkYear(2024)); 
    }
}

Output:

Leap Year
Common Year
Leap Year

Explanation:

  1. Conditional logic checks for leap year rules: divisible by 4 and not 100, or divisible by 400.

Problem#2: Validate User Credentials — Using complex guards in case labels

Validate user credentials where a username must start with admin_, and passwords must be at least 8 characters long.

Solution:

public class CredentialValidator {
    public static String validateCredentials(String username, String password) {
        return switch (username) {
            case String u when u.startsWith("admin_") && password.length() >= 8 ->
                "Credentials are valid.";
            default -> "Invalid username or password!";
        };
    }

    public static void main(String[] args) {
        System.out.println(validateCredentials("admin_user", "strongPass"));
        System.out.println(validateCredentials("admin_user", "weak"));
        System.out.println(validateCredentials("user", "validPassword"));
    }
}

Output:

Credentials are valid.
Invalid username or password.
Invalid username or password.

Explanation:

  1. Complex guards handle conditions like u.startsWith(“admin_”) && password.length() >= 8.
  2. Multi-level validation is achieved with multiple guarded patterns. For a separate comprehensive guide on Guarded Patterns with examples, kindly visit Guarded Pattern in Java 21.

Problem#3: Parse Inputs Based on Format — Using conditional checks & ‘when’ keyword in case labels

Write a program to parse inputs into categories like “Valid Email” or  “Phone Number”. A valid email must have ‘@’ character and a valid phone number must have 10 digits.

Solution:

public class InputParser {
    public static String parseInput(Object input) {
        return switch (input) {
            case String s when s.contains("@") && s.contains(".") -> "Valid Email";
            case String s when s.matches("\\d{10}") -> "Valid Phone Number";
            default -> "Invalid Email or Phone Number";
        };
    }

    public static void main(String[] args) {
        System.out.println(parseInput("user@example.com"));
        System.out.println(parseInput("1234567890"));
        System.out.println(parseInput("invalid_input"));
    }
}

Output:

Valid Email
Valid Phone Number
Invalid Email or phone number

Explanation:

  1. Conditional checks like s.contains(“@”) && s.contains(“.”) and s.matches(“\\d{10}”) classify valid strings.
  2. Default ensures invalid or unsupported types of input.

Problem#4: User Authentication System — Using array pattern in case labels

Implement a system to authenticate users based on different credential types: username/password (String[]), OTP (Integer), or fingerprint (byte[]).

Solution:

public class AuthenticationSystem {
    public static String authenticate(Object credentials) {
        return switch (credentials) {
            case String[] loginDetails when loginDetails.length == 2 -> 
                "Username/Password authentication for user: " + loginDetails[0];
            case Integer otp when otp >= 1000 && otp <= 9999 -> 
                "OTP authentication successful.";
            case byte[] fingerprint when fingerprint.length == 256 -> 
                "Fingerprint authentication successful.";
            default -> "Authentication failed.";
        };
    }

    public static void main(String[] args) {
        System.out.println(authenticate(new String[]{"admin", "password123"}));
        System.out.println(authenticate(1234));
        System.out.println(authenticate(new byte[256]));
        System.out.println(authenticate("XYZ"));
    }
}

Output:

Username/Password authentication for user: admin
OTP authentication successful.
Fingerprint authentication successful.
Authentication failed.

Explanation:

  • Type patterns: Matches credential types (String[], Integer, and byte[]).
  • Guarded patterns: Validates the data within credentials (e.g., otp >= 1000 & <=9999).

Problem#5: Categorize Employees by Age — Using conditional checks in case labels

Given an employee’s age, write a program using Java 17 to categorize them as “Youth (15-25)”, “Mid Level(25-50)”, “Senior (50-65)”, or “Invalid Age (other age)”.

Solution:

public class EmployeeCategorizer {
    public static String categorizeEmployeeAge(Number age) {
        return switch (age) {
            case Integer i when i >= 15 && i < 25 -> "Youth Employee";
            case Integer i when i >= 25 && i <= 50 -> "Mid level Employee";
            case Integer i when i > 50 && i <= 65 -> "Senior Employee";
            default -> "Invalid Age for Employment";
        };
    }

    public static void main(String[] args) {
        System.out.println(categorizeEmployeeAge(22));
        System.out.println(categorizeEmployeeAge(35));
        System.out.println(categorizeEmployeeAge(60));
        System.out.println(categorizeEmployeeAge(80));
    }
}

Output:

Youth Employee
Mid level Employee
Senior Employee
Invalid Age for Employment

Explanation:

  1. The Integer type is matched explicitly, and ranges are handled via guarded patterns like i < 25.
  2. Default ensures invalid or non-integer values are caught.

Problem#6: Temperature Monitoring — Using array pattern in case labels

Write a program to monitor temperature data sent as an array. Use array pattern to handle cases where the array contains high, moderate, or insufficient readings.

Solution:

public class TemperatureMonitor {
    public static String analyzeTemperatures(Object readings) {
        return switch (readings) {
            case int[] temperatures when temperatures.length >= 3 && temperatures[0] > 40 ->
                "High temperatures recorded.";
            case int[] temperatures when temperatures.length == 2 && temperatures[1] <= 20 ->
                "Moderate temperatures recorded.";
            case int[] temperatures when temperatures.length == 1 -> 
                "Insufficient data.";
            default -> "Invalid readings.";
        };
    }

    public static void main(String[] args) {
        System.out.println(analyzeTemperatures(new int[]{42, 38, 45}));
        System.out.println(analyzeTemperatures(new int[]{30, 18}));
        System.out.println(analyzeTemperatures(new int[]{45}));
        System.out.println(analyzeTemperatures(new int[]{}));
    }
}

Output:

High temperatures recorded.
Moderate temperatures recorded.
Insufficient data.
Invalid readings.

Explanation:

  • Array pattern: Matches the type int[].
  • Guarded patterns: Applies conditions like temperatures.length >= 3 and temperatures[0] > 40.

Problem#7: Payment Processing System — Using Multiple Data Types & guarded patterns in case labels

Write a method to process different types of payment methods: 16 digit String for card details, Double for wallet balance, and an Integer[] array for a reward point system.

Solution:

public class PaymentProcessor {
    public static String processPayment(Object payment) {
        return switch (payment) {
            case String cardDetails when cardDetails.length() == 16 -> 
                 "Processing card payment: " + cardDetails;
            case Double walletBalance when walletBalance >= 100.0 -> 
                "You have sufficient balance to procced. Processing wallet payment.";
            case Double walletBalance when walletBalance < 100.0->
                "Insufficient wallet balance.";
            case Integer[] rewardPoints -> 
                "Processing reward points: Points available - " + rewardPoints.length;
            default -> "Unsupported payment data. Kindly provide valid data";
        };
    }

    public static void main(String[] args) {
        System.out.println(processPayment("1234567898765432"));
        System.out.println(processPayment(150.0));
        System.out.println(processPayment(50.0));
        System.out.println(processPayment(new Integer[]{10, 20, 30}));
        System.out.println(processPayment(1234));
    }
}

Output:

Processing card payment: 1234567898765432
You have sufficient balance to procced. Processing wallet payment.
Insufficient wallet balance.
Processing reward points: Points available - 3
Unsupported payment data. Kindly provide valid data

Explanation:

  • Type patterns: String, Double, and Integer[] are used to match payment types.
  • Guarded patterns: Double walletBalance when walletBalance >= 100.0 ensures specific conditions are met before executing the case.

Problem#8: Restaurant Menu Pricing — Using Multiple options in case labels

A restaurant wants to display the price based on a selected menu item.

Solution:

public class MenuPricing {

    private static double extracted(String menuItem) {

       double price = switch (menuItem) {
            case "Burger", "Sandwich", "Wrap" -> 5.99;
            case "Pasta", "Pizza" -> 7.99;
            case "Salad", "Soup" -> 4.99;
            default -> throw new IllegalArgumentException("Unknown menu item: " + menuItem);
        };
        return price;
     }

     public static void main(String[] args) {

        System.out.println("Price of Burger: $" + extracted("Burger"));
        System.out.println("Price of Pizza: $" + extracted("Pizza"));
        System.out.println("Price of Cold Drink: $" + extracted("Cold Drink"));
    }
}

Output:

Price of Burger: $5.99
Price of Pizza: $7.99
Exception in thread "main" java.lang.IllegalArgumentException: Unknown menu item: Cold Drink
at TestJava17Features/test.java17.MenuPricing.extracted(MenuPricing.java:12)
at TestJava17Features/test.java17.MenuPricing.main(MenuPricing.java:21)

Explanation

  • Grouping Case labels: Group items with the same price under a single case.
  • Multiple case labels under a single case reduces boilerplate code.
  • Default case: Throws an exception for invalid menu items.

Problem#9: Using Sealed Classes

Create a hierarchy of shapes (Circle, Rectangle, and Triangle) using a sealed class Shape. Write a method that accepts a Shape object and prints its type.

Solution:


public sealed class Shape permits Circle, Rectangle, Triangle {}

final class Circle extends Shape {}final class Rectangle extends Shape {}final class Triangle extends Shape {}

public class SealedClassDemo {

public static void identifyShape(Shape shape) {

        if (shape instanceof Circle) {
            System.out.println("This is a Circle.");
        } else if(shape instanceof Rectangle) {
            System.out.println("This is a Rectangle.");
        } else if(shape instanceof Triangle) {
            System.out.println("This is a Triangle.");
        }
    }

    public static void main(String[] args) {
        Shape shape1 = new Circle();   
        Shape shape2 = new Rectangle();
        identifyShape(shape1);
        identifyShape(shape2);
    }
}

Explanation:

  • The Shape class restricts which classes can extend it using the sealed keyword.
  • Circle, Rectangle, and Triangle are permits subclasses.
  • The identifyShape() method demonstrates type checking with instanceof.

Problem#10: Variable Patterns in Switch

Write a method that takes an Object and uses a switch statement to print whether it’s an Integer, String, or an unknown type.

Solution:

public class PatternMatchingSwitch {

    public static void identifyObject(Object obj) {

        switch (obj) {
            case Integer i -> System.out.println("It's an Integer: " + i);
            case String s -> System.out.println("It's a String: " + s);
            default -> System.out.println("Unknown type.");
        }
    }

    public static void main(String[] args) {

        identifyObject(10);
        identifyObject("Hello");
        identifyObject(3.14);
    }
}

Output:

It's an Integer: 10
It's a String: Hello
Unknown type.

Explanation:

  • The switch statement uses pattern matching with case Integer i and case String s.
  • The default case handles unknown types.

Problem#11: Sealed Interfaces

Create a sealed interface Vehicle with implementations Car, Bike, and Truck. Write a program to count the number of wheels based on the vehicle type.

Solution:

sealed interface Vehicle permits Car, Bike, Truck {}

final class Car implements Vehicle {}
final class Bike implements Vehicle {}
final class Truck implements Vehicle {}

public class SealedInterfaceDemo {
    public static int countWheels(Vehicle vehicle) {
       return switch (vehicle) {
            case Car c -> 4;
            case Bike b -> 2;
            case Truck t -> 6;
       };
    }

    public static void main(String[] args) {
       Vehicle car = new Car();
       Vehicle bike = new Bike();
       Vehicle truck = new Truck();

       System.out.println("Car has " + countWheels(car) + " wheels.");
       System.out.println("Bike has " + countWheels(bike) + " wheels.");
       System.out.println("Truck has " + countWheels(truck) + " wheels.");
    }
}

Output:

Car has 4 wheels.
Bike has 2 wheels.
Truck has 6 wheels.

Explanation:

  • The switch expression determines the wheel count using type patterns.

Problem#12: Using Type Patterns in Switch

Write a program to categorize objects as Number, String, or Unknown using switch type patterns.

Solution:

public class TypePatternSwitch {

    public static String categorize(Object obj) {

        return switch (obj) {
            case Number n -> "Number: " + n;
            case String s -> "String: " + s;
            default -> "Unknown type.";
        };
    }

    public static void main(String[] args) {

        System.out.println(categorize(42));
        System.out.println(categorize("Java 17"));
        System.out.println(categorize(true));
    }
}

Output:

Number: 42
String: Java 17
Unknown type.

Explanation:

  • The switch statement checks for Number and String using type patterns.

Problem#13: Extending Sealed Classes

Add another subclass Polygon to a hierarchy of shapes (Circle, Rectangle, and Triangle) using a sealed class Shape. Demonstrate how adding a new subclass affects existing switch statements.

Solution:

sealed class Shape permits Circle, Rectangle, Triangle, Polygon {}

final class Circle extends Shape {}
final class Rectangle extends Shape {}
final class Triangle extends Shape {}
final class Polygon extends Shape {}


public class ExtendedSealedClass {

    private static void extractedShape(Shape shape){

         switch (shape) {  
            case Circle c -> System.out.println("Circle");  
            case Rectangle r -> System.out.println("Rectangle");
            case Triangle t -> System.out.println("Triangle"); 
            case Polygon p -> System.out.println("Polygon"); 
            default -> System.out.println("Unknown Shape");  
         }
    }

    public static void main(String[] args) {
       Shape polygon = new Polygon();
       extractedShape(polygon);       
    }
}

Output:

Polygon

Explanation:

  • Adding Polygon requires updating the switch statement to handle this new type explicitly.

Problem#14: Handling Null in Type Patterns

Write a method that uses a switch with a type pattern and handles null values.

Solution:

public class NullHandlingSwitch {

    public static void handleObject(Object obj) {

        switch (obj) {
            case null -> System.out.println("It's null.");
            case String s -> System.out.println("String: " + s);
            case Integer i -> System.out.println("Integer: " + i);
            default -> System.out.println("Unknown type.");
        }
    }

    public static void main(String[] args) {
        handleObject(null);
        handleObject("Java 17");
        handleObject(100);
    }
}

Output:

It's null.
String: Java 17
Integer: 100

Explanation:

  • Java 17 allows null handling in switch cases.

Problem#15: Combining Sealed Classes and Enum Switch

Create a sealed class hierarchy for transportation modes (Car, Bike, and Train). Add an enum for fuel types (PETROL, CNG, ELECTRIC, UNKNOWN). Write a program that prints the fuel type based on the transportation mode using a switch expression.

Solution:

sealed class Transport permits Car, Bike, Train {}

final class Car extends Transport {}
final class Bike extends Transport {}
final class Train extends Transport {}

enum FuelType {
    PETROL, DIESEL, ELECTRIC, UNKNOWN;
}

public class TransportFuelDemo {
   public static FuelType getFuelType(Transport transport) {
      return switch (transport) {
          case Car c -> FuelType.CNG;
          case Bike b -> FuelType.PETROL;
          case Train t -> FuelType.ELECTRIC;
          default -> FuelType.UNKNOWN;

      };
   }

   public static void main(String[] args) {
      Transport car = new Car();
      Transport train = new Train();
      System.out.println("Car fuel: " + getFuelType(car));
      System.out.println("Train fuel: " + getFuelType(train));
   }
}

Output:

Car fuel: PETROL
Train fuel: ELECTRIC

Explanation:

  • Sealed classes (Transport) ensure strict type hierarchies.
  • A switch expression is used to map each transport type to a specific FuelType.

Problem#16: Combining Type Patterns with Sealed Classes

Create a sealed class hierarchy for file types (TextFile, ImageFile, and VideoFile). Use a switch statement to categorize files and their extensions.

Solution:

sealed class File permits TextFile, ImageFile, VideoFile {}

final class TextFile extends File {}
final class ImageFile extends File {}
final class VideoFile extends File {}

public class FileCategorization {
    public static void printFileType(File file, String extension) {
       switch (file) {
          case TextFile t -> System.out.println("Text File with extension: " + extension);
          case ImageFile i -> System.out.println("Image File with extension: " + extension);
          case VideoFile v -> System.out.println("Video File with extension: " + extension);
          default -> System.out.println("Unknown File with unknown extension");
       }
    }

    public static void main(String[] args) {
        File file1 = new TextFile();
        File file2 = new ImageFile();
        File file3 = new VideoFile();

        printFileType(file1, ".txt");
        printFileType(file2, ".jpg");
        printFileType(file3, ".mp4");
    }
}

Output:

Text File with extension: .txt
Image File with extension: .jpg
Video File with extension: .mp4

Explanation:

  • The sealed class (File) restricts file types to specific categories.
  • The switch statement categorizes files based on their type and extension.

Problem#17: Enhanced Random Generators

Use the new RandomGenerator interface to generate random numbers from different generators.

Solution:

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

public class RandomGeneratorDemo {
publicstatic void generateRandomNumbers() {
        RandomGenerator random = RandomGeneratorFactory.of("L128X256MixRandom").create();
        System.out.println("Random Double: " + random.nextDouble());
        System.out.println("Random Int: " + random.nextInt(100));
    }

    public static void main(String[] args) {
        generateRandomNumbers();
    }
}

Output:

Random Double: 0.49454839058699296
Random Int: 5

Explanation:

  • The RandomGenerator interface provides a unified API for random number generators.
  • The RandomGeneratorFactory allows dynamic selection of different algorithms.

Problem#18: Using java.util.random for Stream Operations

Generate a stream of random numbers using the RandomGenerator interface and process them.

Solution:

import java.util.random.RandomGenerator;

public class RandomStreamDemo {
    public static void main(String[] args) {
       RandomGenerator generator = RandomGenerator.of("Xoshiro256PlusPlus");

       generator.doubles(5, 0.0, 1.0)
               .forEach(System.out::println);
    }
}

Output:

0.9114784320431131
0.41720323668353565
0.9926844540795896
0.4088717505767786
0.8375313357431428

Explanation:

  • The doubles() method generates a stream of random doubles within a specified range.
  • This showcases Java 17’s enhancements for random number generation in streams.

Problem#19: New Features in String API

Write a program to use the String.stripIndent() method and explain how it works.

Solution:

public class StringFeaturesDemo {
    public static void main(String[] args) {
        String multiline = """
            Line 1
                Line 2
                    Line 3
            """;

        System.out.println("Original:\n" + multiline);
        System.out.println("After stripIndent:\n" + multiline.stripIndent());
    }
}

Output:

Original:
Line 1
     Line 2
          Line 3

After stripIndent:
Line 1
     Line 2
          Line 3

Explanation:

  • stripIndent() removes incidental white spaces common to all lines in a multi-line string.
  • It is particularly useful for cleaning up text block formatting.

Problem#20: Vehicle Specification Checker — Using Record Pattern

Write a program to create a record ‘Car’ containing brand and speed fields using Java 17, and print “Car: <brand> at <speed> km/h”.

Solution:

record Car(String brand, int speed) {}

public class VehicleSpecificationChecker {
    public static void main(String[] args) {
        Object vehicleData = new Car("Toyota", 120);

        switch (vehicleData) {
            case Car(String brand, int speed) -> 
                System.out.println("Car: " + brand + " at " + speed + " km/h");
            default -> 
                System.out.println("Unsupported vehicle data");
        }
    }
}

Output:

Car: Toyota at 120 km/h

Explanation:

A record pattern (Car(String brand, int speed)) extracts data fields directly.

Problem#21: A switch-case construct without ‘default’ case

Is it mandatory to write default case always while using enhanced switch-case construct? If not, demonstrate the situation with an example.

In Java’s enhanced switch statement, the default case is not compulsory if The cases in the switch statement cover all possible values of the input. This often happens with enums or sealed classes where all permitted values are explicitly listed. For example:

enum Example: 

enum Day { MONDAY, TUESDAY, WEDNESDAY; }

public static void describeDay(Day day) {
   switch (day) {
      case MONDAY -> System.out.println("Start of the week");
      case TUESDAY -> System.out.println("Second day");
      case WEDNESDAY -> System.out.println("Midweek");
   }
}

Here, no default is required because all Day values are handled.

Sealed Classes Example:

sealed interface Vehicle permits Car, Bike, Truck {}

final class Car implements Vehicle {}
final class Bike implements Vehicle {}
final class Truck implements Vehicle {}

public static void describeVehicle(Vehicle vehicle) {
    switch (vehicle) {
       case Car c -> System.out.println("This is a car.");
       case Bike b -> System.out.println("This is a bike.");
       case Truck t -> System.out.println("This is a truck.");
    }
}

Here, Vehicle is a sealed interface, which means it restricts the types that can implement it. Only Car, Bike, and Truck are permitted. Since all possible types of Vehicle (Car, Bike, and Truck) are explicitly handled in the switch statement, no default case is needed.

♥ For non-exhaustive cases (e.g., String or int), a default is required to ensure all possibilities are accounted for.


Java 17 Coding Interview Questions and Solutions: Complex Problems

Problem#1: Handling Complex Data Formats in a Financial System

Suppose, you are building a financial analytics system where the input can vary widely depending on the source. The system must process the input data and classify it based on the following possibilities:

  1. Single numeric value: Represents a monetary amount (e.g., Double or Integer).
  2. Array of values: Represents multiple transactions (e.g., int[] or double[]).
  3. Record-based input: Represents detailed transaction metadata (e.g., TransactionRecord).
  4. String input: Represents raw data or descriptions.

Using the following rules, implement the classification logic:

  • Single integers should be labeled as “Single Integer: Processed”.
  • Single doubles should be labeled as “Single Double: Rounded to 2 decimal places”.
  • Arrays should be labeled with their type and size, such as “Integer Array of size 3”.
  • Transactions in record format should extract the transaction type and print it.
  • Strings are logged as “Raw Data”.

Solution

record TransactionRecord(String transactionType, double amount) {}

public class FinancialSystem {
    
    private static String extracted(Object inputData) {
        String result = switch (inputData) {
            case Integer i -> "Single Integer: Processed -> " + i;
            case Double d -> "Single Double: Rounded to 2 decimal places -> " + String.format("%.2f", d);
            case int[] arr -> "Integer Array of size " + arr.length;
            case double[] arr -> "Double Array of size " + arr.length;
            case TransactionRecord(String type, double amount) -> 
                "Transaction Type: " + type + ", Amount: " + amount;
            case String s -> "Raw Data -> " + s;
            default -> "Unsupported data type";
        };
        return result;
    }

    public static void main(String[] args) { 
       System.out.println(extracted(new TransactionRecord("Credit", 1250.75)));
       System.out.println(extracted(2450.755678));
       System.out.println(extracted(new double[] {29.57, 76.48, 92.38}));
       System.out.println(extracted("Raw Data-1"));
       System.out.println(extracted(2450.75f));
    }
}

Output:

Transaction Type: Credit, Amount: 1250.75
Single Double: Rounded to 2 decimal places -> 2450.76
Double Array of size 3
Raw Data -> Raw Data-1
Unsupported data type

Explanation:

  1. Record Pattern (TransactionRecord):
    • The switch case TransactionRecord(String type, double amount) extracts the transactionType and amount fields from the record. It prints details about the transaction type and amount.
  2. Type Patterns (Integer, Double):
    • The cases Integer i and Double d classify numeric inputs based on their type.
    • For Double, the value is rounded to two decimal places using String.format.
  3. Array Patterns (int[], double[]):
    • Arrays of integers and doubles are matched separately. The arr.length property dynamically determines the size.
  4. Fallback Case (default):
    • Any unhandled input types are classified under the “Unsupported data type” category.

Problem#2: Retail Management System

Suppose, you are designing a retail management system. The system classifies payment methods and products and calculates discounts based on various criteria. Below are the specifications:

  1. Products can be of type Electronics, Clothing, or Food.
  2. Payment methods are CreditCard, DebitCard, or UPI.
  3. Apply a discount of 20% if the payment method is UPI and the total is above $100.
  4. Handle cases where a product belongs to multiple categories like “Phone”, “Tablet”, “Laptop”, or “Smartwatch”, and set them under “Electronics”.
  5. Lists of expensive products (above $500) should be identified using record patterns.
  6. For year end discount validation, use a ternary operator to determine if the discount is applicable for the year end or not.
  7. Use a sealed interface ProductType to represent product categories.

Solution: 

import java.util.List;

sealed interface ProductType permits Electronics, Clothing, Food {}

final class Electronics implements ProductType {
    
    String name;
    Electronics(String name) { this.name = name; }
    @Override
    public String toString() { return "Electronics: " + name; }
}

final class Clothing implements ProductType {

    String size;
    Clothing(String size) { this.size = size; }

    @Override
    public String toString() { return "Clothing Size: " + size; }
}

final class Food implements ProductType {

    String expiryDate;
    Food(String expiryDate) { this.expiryDate = expiryDate; }

    @Override
    public String toString() { return "Food Expiry Date: " + expiryDate; }
}

record DiscountedProduct(String name, double price) {}

public class RetailSystem {

   public static void main(String[] args) {

      Object item = new Electronics("Smartphone");
      String payment = "UPI";
      double total = 150.0;
      int month = 12;

      List<DiscountedProduct> products = listofDiscountedProducts();
      extractedItem(item);
      extractedPayment(payment, total, month);
      extractedProduct(products);

    }

    private static void extractedProduct(List<DiscountedProduct> products) {

        for (var p : products) {
           switch (p) {
              case DiscountedProduct dp when dp.price() > 500 -> 
                    System.out.println("Expensive: " + dp.name());
              default -> System.out.println("Affordable: " + p.name());
           }
        }
     }

     private static List<DiscountedProduct> listofDiscountedProducts() {

         List<DiscountedProduct> products = List.of(
             new DiscountedProduct("Laptop", 1000.0),
             new DiscountedProduct("Jeans", 50.0),
             new DiscountedProduct("Smartphone", 600.0)
         );
         return products;
     }

     private static void extractedPayment(String payment, double total, int month) {

         switch (payment) {
             case "CreditCard", "DebitCard" -> System.out.println("No extra discount");
             case "UPI" -> {
                boolean yearEndDiscount = (month == 12);
                String discountMsg = yearEndDiscount ? "Extra year end sale discount applied" : "No year end sale discount";
                System.out.println("UPI Payment - " + discountMsg);
                if (total > 100) System.out.println("20% Discount Applied");
             }
             default -> System.out.println("Invalid payment method");
         }
     }

     private static void extractedItem(Object item) {

         switch (item) {
            case Electronics e -> System.out.println(e + " - Category: Electronics");
            case Clothing c -> System.out.println(c + " - Category: Clothing");
            case Food f -> System.out.println(f + " - Category: Food");
            default -> System.out.println("Unknown category");
         }
     }
}

Output: 

Electronics: Smartphone - Category: Electronics
UPI Payment - Extra year end sale discount applied
20% Discount Applied
Expensive: Laptop
Affordable: Jeans
Expensive: Smartphone

Explanation:

This code provides a flexible way to handle diverse features of Java 17 while maintaining clean and readable code. It highlights the powerful capabilities of pattern matching introduced in Java 17.

You may also go through:  ‘How to migrate From Java 8 to Java 17‘.

For Java 17 concepts interview questions, kindly visit Java 17 Interview Questions & Answers Explained.


References: https://www.oracle.com/java/technologies/javase/17-relnote-issues.html

Leave a Reply


Top