Explain Codes LogoExplain Codes Logo

Is it possible to use the instanceof operator in a switch statement?

java
pattern-matching
type-checking
best-practices
Anton ShumikhinbyAnton Shumikhin·Oct 18, 2024
TLDR

Java 17 ushers in pattern matching for switch. It integrates instanceof-like checks directly within a switch case:

Object obj = // ...; switch (obj) { case String s -> System.out.println(s.length()); case Integer i -> System.out.println(i); default -> System.out.println("Unknown"); }

This niftily binds the object to a variable whenever it matches the type pattern, simplifying type assessment and casting. Remember, this is a preview feature; turn it on with the --enable-preview compiler flag.

Maximizing with type-checking

Java 17's new pattern matching capabilities are a shift towards less boilerplate, safely sidestepping type casting and enhancing maintainability. It's not just syntactical sugar: it's a sizable upgrade. For those reliant on multiple if...else constructs for type checks, this is a game-changer.

Good old polymorphism and visitor pattern

We get it — not everyone can jump ship to Java 17 just yet. This is where good old patterns like subtype polymorphism, interfaces and the visitor pattern come into play. They're still key players in scenarios where switching based on type is yet not feasible or when handling legacy code.

Enum-it-out for varying behavior

"Effective Java" by Joshua Bloch champions the underdog: enums with abstract methods. This approach ticks all the boxes for the open-closed principle and keeps the type-based behavior nicely organized.

Safe landing for unknown types

The getOrDefault method in a Map gracefully tackles any unknown types, providing a failsafe. This keeps our application resilient and ready for surprises.

Class-to-function mapping

For varying behaviors across types, consider class-to-function mapping. It's a lunch pack of functional interfaces and Consumer patterns, simplifying branching and maintaining each type's behavior in neat little pockets:

Map<Class<?>, Consumer<Object>> behaviorMap = Map.of( String.class, obj -> System.out.println("String logic"), // Not just any string. It's THE String! Integer.class, obj -> System.out.println("Integer logic"), // Because who doesn't love counting! Object.class, obj -> System.out.println("Generic logic") // Every hero needs a catch-all clause! ); behaviorMap.getOrDefault(myVar.getClass(), behaviorMap.get(Object.class)).accept(myVar); // Now serving: Type-based behavior!

These shine the light on error-prone code, guiding you towards clearer, maintainable, and extendable solutions.