Java 14 - Pattern Matching for InstanceOf (Preview)


Java release train is running and delivering new java features faster that the past. Java 14 became GA on March 17, 2020 with some new features. In this post, we will look at a preview feature introduced with Java 14 - Pattern Matching for InstanceOf.

All java developers are aware of instanceOf operator in java. Let’s consider following class hierarchy for greeting a person.

Greet class diagram

In general, the instanceOf usage with these classes would look something like following code -

Listing 1: Using instanceOf to greet
  public static String greetingMessage(Greet greet) {
    greet.greet();
    if (greet instanceof PhysicalHandshake) {               (1)
      PhysicalHandshake phs = (PhysicalHandshake) greet;    (2)
      return phs.extendHand();                              (3)
    } else if (greet instanceof Namaste) {
      Namaste nm = (Namaste) greet;
      return nm.joinHands();
    }
    return "Hello";
  }
1 Check the type with instanceOf
2 Cast to local variable
3 Use the type casted variable

Testing our code:

Listing 1.Test: Using instanceOf to greet - Test
  @Test
  void greetingMessageHandshake() {
    PhysicalHandshake hs = new PhysicalHandshake();
    Assertions.assertThrows(IllegalArgumentException.class,
        () -> JEP305PatternMatchingInstanceOf.greetingMessage(hs),
        "Access to hands is not allowed. It is unsafe and could spread COVID-19!");
  }

  @Test
  void greetingMessageNamaste() {
    Namaste nm = new Namaste();
    Assertions.assertEquals(JEP305PatternMatchingInstanceOf.greetingMessage(nm),
        "Join your own hands! It helps to prevent COVID-19!");
  }

Pattern Matching for instanceOf

A pattern Matching for instanceOf in Java 14 is simple - If the type of a target matches, then it is assigned to a specified single binding variable. This combines instance check and variable assignment into single line.

target instanceOf referenceType varName

If target instance is of of type referenceType, then cast it in to referenceType and assign to varName variable.

For example, if we apply it to earlier example for PhysicalHandshake, it would look like this -

Listing 2: Pattern Matching for instanceOf example - 1
  public static String greetingMessage14(Greet greet) {
    greet.greet();
    if (greet instanceof PhysicalHandshake phs){ (1)
      return phs.extendHand(); (2)
    } else if (greet instanceof Namaste nm){
      return nm.joinHands();
    }
    return "Hello"; (3)
  }
1 This uses new pattern matching to combine instance check and variable assignment.
2 phs is of type PhysicalHandshake and available for accessing. Execution comes here if and only if greet is of type PhysicalHandshake.
3 phs is not accessible here.

Testing our code:

Listing 2.Test: Pattern Matching for instanceOf example - 1 Test
  @Test
  void greetingMessageHandshake14() {
    PhysicalHandshake hs = new PhysicalHandshake();
    Assertions.assertThrows(IllegalArgumentException.class,
        () -> JEP305PatternMatchingInstanceOf.greetingMessage14(hs),
        "Access to hands is not allowed. It is unsafe and could spread COVID-19!");
  }

  @Test
  void greetingMessageNamaste14() {
    Namaste nm = new Namaste();
    Assertions.assertEquals(JEP305PatternMatchingInstanceOf.greetingMessage14(nm),
        "Join your own hands! It helps to prevent COVID-19!");
  }
instanceOf of behavior for null values is unchanged. If target object is null, checks fails and variable is not assigned with any value.

Scope of an instance variable

Scope of instance variable depends on the type of expressions inside if. The scope is usually limited to the true block with one exception.

True block

Chain conditions with && operator

When using && to chain multiple conditions, variable is available to subsequent chain conditions as well as inside the true block.

Consider following example -

Listing 3: Pattern Matching for instanceOf example - 2
  public static String greetingMessageVirtual(Greet greet) {
    greet.greet();
    if (greet instanceof Handshake hs && hs.isVirtual()){ (1)
      return hs.virtualGreet();
    }
    return "Hello";
  }
1 The variable hs on the right hand side of the && is the one assigned from pattern matching for instanceOf. As usual, RHS of && is only evaluated if target check succeeds.

Testing our code:

Listing 3.Test: Pattern Matching for instanceOf example - 2 Test
  @Test
  void greetingMessageVirtual() {
    Handshake hs = new Handshake();
    Assertions.assertEquals(JEP305PatternMatchingInstanceOf.greetingMessageVirtual(hs),
        "Virtual greet is always safe!");
  }

Chain conditions with || operator

Scope of the pattern matching variable changes when using || operator.

Consider following example -

Listing 4: Pattern Matching for instanceOf example - 3
  static Namaste hs = new Namaste(); (1)
  public static String greetingMessage14VirtualOnly(Greet greet) {
    greet.greet();
    if (greet instanceof Handshake hs || hs.isVirtual()){ (2)
      return hs.virtualGreet();
    }
    return "Hello";
  }
1 Declares a static class variable hs of type Namaste.
2 In this case, hs variable on the RHS of || refers to the static class variable and not hs in pattern matching. Also, the true block does not get pattern matching variable and refers to static variable.
Pattern matching variable when used with ||, is limited to its declaration only and is not available anywhere else in the code block or other || conditions.

Testing our code:

When target instance does not evaluate to true for pattern test but RHS of || using static class variable evaluates to true, static greet is used.

Listing 4.Test: Pattern Matching for instanceOf example - 3 Test
  @Test
  void greetingMessage14VirtualOnly() {
    PhysicalHandshake phs = new PhysicalHandshake();
    Assertions.assertEquals(JEP305PatternMatchingInstanceOf.greetingMessage14VirtualOnly(phs),
        "Virtual greet is always safe!");
  }

Conclusion

In this post, we learned how to leverage pattern matching for instanceOf in Java 14. This new feature will help us avoid writing explicit type casts.

The source for this is available in github - manikmagar/java14-examples. List of all features for Java 14 can be found here.

Have any thoughts about this article? Let me know in comments or on twitter.

Greeting classes intentionally use messages related to the COVID-19 and are for awareness purpose only. Please see official instructions for how to stay safe and healthy.
on twitter to get updates on new posts.

Lives on Java Planet, Walks on Java Streets, Read/Writes in Java, JCP member, Java EE enthusiast, MuleSoft Integration Consultant, Open Source Contributor and Supporter, also writes at Unit Testers, A Family man!