Combining assert statement and instanceof pattern matching

In Java 19, I’m trying to use instanceof pattern matching inside an assert statement.
I would expect the matched type would be available after the statement, but the Java compiler does not recognize the new variable.

We create a variable Object obj, and we cannot know whether it contains an Integer or a String.
We pass the variable to two test methods.

public class AssertPatternMatching {
    public static void main(String[] args) {
        Object obj = args.length == 0 ? Integer.valueOf(42) : "Hello";

        afterAssert(obj);
        insideMessage(obj);
    }

In method afterAssert(), we assert that obj is a String, and bind the string to the new variable str via instanceof pattern matching.
I would expect str to be known and usable in the next line.
However, the compiler does not know symbol str.

    private static void afterAssert(Object obj) {
        assert obj instanceof String str;
        str.length(); // javac: cannot find symbol variable str
    }

In method insideMessage(), we use a convoluted assert statement to check that obj is not a String. If it would be, the assertion fails, and we can provide a message.
As the instanceof check is negated, pattern matched str variable should be available for the error message.
However, the compiler again does not know symbol str.

    private static void insideMessage(Object obj) {
        assert !(obj instanceof String str) : "Is a string: " + str.length();
        // line above: javac: cannot find symbol variable str
        obj.hashCode();
    }

It works if we replace assert statements with if:

private static void afterAssertIf(Object obj) {
    if(obj instanceof String str) {
        str.length();
    } else {
        throw new AssertionError();
    }
}

private static void insideMessageIf(Object obj) {
    if (!(obj instanceof String str)) {
        obj.hashCode();
    } else {
        throw new AssertionError("Is a string: "+ str.length());
    }
}

The insideMessage() example is really an edge case, so I understand it’s not supported.
I would have expected afterAssert() to work, however.
Is this a deliberate design choice or a bug?
If deliberate, what’s the rationale?

Complete code at https://gist.github.com/enikao/57bb1b10ce3126494ec4baa2bc7db2df

>Solution :

assert statements are only executed when assertions are enabled with -ea. Without -ea, the code is not executed, therefore the variable is never assigned/does not exist (this is the default).

private static void afterAssert(Object obj) {
    assert obj instanceof String;
    ((String) str).length();
}

Leave a Reply