Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

    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();
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading