When processing heterogeneous collections or API responses, you often need to check types and cast objects repeatedly. instanceof pattern matching combines type checking and casting into a single operation, eliminating redundant code and potential ClassCastException bugs.

Old vs New Style

OldVsNew.java
Replay: real traced execution (multi-file project)
public class OldVsNew {
    static void oldStyle(Object obj) {
        if (obj instanceof String) {
            String s = (String) obj;  // redundant cast
            System.out.println("OLD: " + s.toUpperCase());
        }
    }

    static void newStyle(Object obj) {
        if (obj instanceof String s) {
            System.out.println("NEW: " + s.toUpperCase());
        }
    }

    public static void main(String[] args) {
        Object obj = "pattern matching";
        oldStyle(obj);
        newStyle(obj);
    }
}
  1. obj ← pattern matching

    15public static void main(String[] args) {16    Object obj→ pattern matching = "pattern matching";17    oldStyle(objpattern matching);18    newStyle(obj);
  2. static void oldStyle(Object obj)

    1public class OldVsNew {2    static void oldStyle(Object objpattern matching) {3        if (obj instanceof String) {
  3. s ← pattern matching

    2static void oldStyle(Object obj) {3    if (obj instanceof String) {4        String s→ pattern matching = (String) obj;  // redundant cast5        System.out.println("OLD: " + s.toUpperCase());6    }
    outputOLD: PATTERN MATCHING
  4. oldStyle(obj);

    16    Object obj = "pattern matching";17    oldStyle(objpattern matching);18    newStyle(objpattern matching);19}
  5. static void newStyle(Object obj)

    9static void newStyle(Object objpattern matching) {10    if (obj instanceof String s) {
  6. if (obj instanceof String s)

    9static void newStyle(Object obj) {10    if (obj instanceof String s) {11        System.out.println("NEW: " + s.toUpperCase());12    }
    outputNEW: PATTERN MATCHING
  7. newStyle(obj);

    17    oldStyle(obj);18    newStyle(objpattern matching);19}

The pattern variable s is automatically cast and scoped to the if block.

pattern_variable A pattern variable is automatically declared, cast, and scoped when the instanceof test succeeds.

Basic Usage

obj
Basic.java
Replay: real traced execution (multi-file project)
public class Basic {
    public static void main(String[] args) {
        Object obj = "hello";
        if (obj instanceof String s) {
            System.out.println("Length: " + s.length());
            System.out.println("Upper: " + s.toUpperCase());
        }
    }
}
public class Basic {
    public static void main(String[] args) {
        Object obj = "pattern matching";
        if (obj instanceof String s) {
            System.out.println("Length: " + s.length());
            System.out.println("Upper: " + s.toUpperCase());
        }
    }
}
public class Basic {
    public static void main(String[] args) {
        Object obj = 123;
        if (obj instanceof String s) {
            System.out.println("Length: " + s.length());
            System.out.println("Upper: " + s.toUpperCase());
        }
    }
}
  1. obj ← hello

    1public class Basic {2    public static void main(String[] args) {3        Object obj→ hello = "hello"; //@obj="hello", "pattern matching", 1234        if (obj instanceof String s) {
  2. if (obj instanceof String s)

    3Object obj = "hello"; //@obj="hello", "pattern matching", 1234if (obj instanceof String s) {5    System.out.println("Length: " + s.length());6    System.out.println("Upper: " + s.toUpperCase());7}
    outputLength: 5
    Upper: HELLO
  1. obj ← pattern matching

    1public class Basic {2    public static void main(String[] args) {3        Object obj→ pattern matching = "pattern matching";4        if (obj instanceof String s) {
  2. if (obj instanceof String s)

    3Object obj = "pattern matching";4if (obj instanceof String s) {5    System.out.println("Length: " + s.length());6    System.out.println("Upper: " + s.toUpperCase());7}
    outputLength: 16
    Upper: PATTERN MATCHING
  1. obj ← 123

    1public class Basic {2    public static void main(String[] args) {3        Object obj→ 123 = 123;4        if (obj instanceof String s) {

Benefits

  • No redundant cast: type checking and casting happen together
  • Shorter code: fewer lines, clearer intent
  • Safer: compiler ensures the pattern variable is only used where valid

Scope Rules

The pattern variable is in scope where the instanceof test is definitely true:

obj
Scope.java
Replay: real traced execution (multi-file project)
public class Scope {
    public static void main(String[] args) {
        Object obj = "scoped";
        if (obj instanceof String s) {
            System.out.println("In if: " + s);
        }
        if (obj instanceof String s && s.length() > 3) {
            System.out.println("Length check: " + s);
        }
        if (!(obj instanceof String s)) {
        } else {
            System.out.println("In else: " + s);
        }
    }
}
public class Scope {
    public static void main(String[] args) {
        Object obj = "hi";
        if (obj instanceof String s) {
            System.out.println("In if: " + s);
        }
        if (obj instanceof String s && s.length() > 3) {
            System.out.println("Length check: " + s);
        }
        if (!(obj instanceof String s)) {
        } else {
            System.out.println("In else: " + s);
        }
    }
}
  1. obj ← scoped

    1public class Scope {2    public static void main(String[] args) {3        Object obj→ scoped = "scoped"; //@obj="scoped", "hi"4        if (obj instanceof String s) {
  2. if (obj instanceof String s)

    3Object obj = "scoped"; //@obj="scoped", "hi"4if (obj instanceof String s) {5    System.out.println("In if: " + sscoped);6}
    outputIn if: scoped
  3. if (obj instanceof String s && s.length() > 3)

    6}7if (obj instanceof String s && s.length() > 3) {8    System.out.println("Length check: " + sscoped);9}
    outputLength check: scoped
  4. else

    10if (!(obj instanceof String s)) {11} else {12    System.out.println("In else: " + sscoped);13}
    outputIn else: scoped
  1. obj ← hi

    1public class Scope {2    public static void main(String[] args) {3        Object obj→ hi = "hi";4        if (obj instanceof String s) {
  2. if (obj instanceof String s)

    3Object obj = "hi";4if (obj instanceof String s) {5    System.out.println("In if: " + shi);6}
    outputIn if: hi
  3. else

    10if (!(obj instanceof String s)) {11} else {12    System.out.println("In else: " + shi);13}
    outputIn else: hi
scope_flow Pattern variables follow "flow scoping" - they are in scope wherever the compiler can prove the pattern matched.

Null Safety

NullSafe.java
Replay: real traced execution (multi-file project)
public class NullSafe {
    static void process(Object obj) {
        if (obj instanceof String s) {
            System.out.println("String: " + s);
        } else {
            System.out.println("Not a string (or null)");
        }
    }

    public static void main(String[] args) {
        process("hello");
        process(123);
        process(null);  // instanceof is false for null
    }
}
  1. public static void main(String[] args)

    10public static void main(String[] args) {11    process("hello");12    process(123);
  2. static void process(Object obj)

    pass 1 of 3
    1public class NullSafe {2    static void process(Object objhello) {3        if (obj instanceof String s) {
    All 3 passes — pass 1 is the card above
    passobjs
    1hellohello
    2123
    3null
  3. if (obj instanceof String s)

    2static void process(Object obj) {3    if (obj instanceof String s) {4        System.out.println("String: " + shello);5    } else {
    outputString: hello
  4. process("hello");

    10public static void main(String[] args) {11    process("hello");12    process(123);13    process(null);  // instanceof is false for null
  5. else

    pass 1 of 2
    4    System.out.println("String: " + s);5} else {6    System.out.println("Not a string (or null)");7}
    outputNot a string (or null)
  6. process(123);

    11    process("hello");12    process(123);13    process(null);  // instanceof is false for null14}
  7. else

    pass 2 of 2
    4    System.out.println("String: " + s);5} else {6    System.out.println("Not a string (or null)");7}
    outputNot a string (or null)
  8. process(null); // instanceof is false for null

    12    process(123);13    process(null);  // instanceof is false for null14}

Multiple Type Checks

MultipleTypes.java
Replay: real traced execution (multi-file project)
public class MultipleTypes {
    static String describe(Object obj) {
        if (obj instanceof String s) {
            return "String of length " + s.length();
        } else if (obj instanceof Integer i) {
            return "Integer value " + i;
        } else if (obj instanceof Double d) {
            return "Double value " + d;
        } else {
            return "Unknown type";
        }
    }

    public static void main(String[] args) {
        System.out.println(describe("hello"));
        System.out.println(describe(42));
        System.out.println(describe(3.14));
        System.out.println(describe(true));
    }
}
  1. public static void main(String[] args)

    14public static void main(String[] args) {15    System.out.println(describe("hello"));16    System.out.println(describe(42));
  2. static String describe(Object obj)

    pass 1 of 4
    1public class MultipleTypes {2    static String describe(Object objhello) {3        if (obj instanceof String s) {
    All 4 passes — pass 1 is the card above
    passobjid
    1hello
    24242
    33.143.14
    4true
  3. System.out.println(describe("hello"));

    14public static void main(String[] args) {15    System.out.println(describe("hello"));16    System.out.println(describe(42));17    System.out.println(describe(3.14));
    outputString of length 5
  4. if (obj instanceof Integer i)

    4    return "String of length " + s.length();5} else if (obj instanceof Integer i) {6    return "Integer value " + i42;7} else if (obj instanceof Double d) {
  5. System.out.println(describe(42));

    15System.out.println(describe("hello"));16System.out.println(describe(42));17System.out.println(describe(3.14));18System.out.println(describe(true));
    outputInteger value 42
  6. if (obj instanceof Double d)

    6    return "Integer value " + i;7} else if (obj instanceof Double d) {8    return "Double value " + d3.14;9} else {
  7. System.out.println(describe(3.14));

    16    System.out.println(describe(42));17    System.out.println(describe(3.14));18    System.out.println(describe(true));19}
    outputDouble value 3.14
  8. System.out.println(describe(true));

    17    System.out.println(describe(3.14));18    System.out.println(describe(true));19}
    outputUnknown type

Exercise: Practical.java

Create a method that processes a list of Objects and returns formatted strings based on their actual types