Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assert for null check

Tags:

java

It seems widely accepted that assert statements should be reserved for testing and disabled in production because errors should have been resolved by then, and enabling assertions affects performance. However surely the same could be said of null checks with if statements. Why is this code considered good for production

if(x != null) {
    x.setId(idx);
    if (y != null) {
        if (y.id == x.id) {
            x.doSth();
        }
    } else {
        //handle error
    }
} else {
    //handle error
}

but this code isn't? (Assuming assertions are enabled)

try {
    assert(x != null); 
    x.setId(idx);
    assert(y != null);
    if (y.id == x.id) {
        x.doSth();
    }
} catch (AssertionError e) {
    //handle error
}

I understand using an if statement when it's expected that a variable may not be initialized. However when it's for defensive coding, assert seems more elegant and readable.

I also tested performance for each method with this:

public class AssertTest {

    static final int LOOPS = 10000000;

    public static void main(String[] args) {

            String testStr = "";

            long startNotEqualsTest = System.currentTimeMillis();
            for (int i = 0; i < LOOPS; i++) {
                if (testStr != null) {
                    testStr = System.currentTimeMillis() + "";
                } else {
                    throw new RuntimeException("We're doomed");
                }
            }
            long notEqualsTestDuration = System.currentTimeMillis() - startNotEqualsTest;

            testStr = "";

            long startAssertTest = System.currentTimeMillis();      
            for (int i = 0; i < LOOPS; i++) {
                try {
                    assert(testStr != null);
                    testStr = System.currentTimeMillis() + "";
                } catch (AssertionError e) {
                    throw new RuntimeException("We're doomed");
                }
            }
            long assertTestDuration = System.currentTimeMillis() - startAssertTest;

            System.out.println("Duration with if : " + notEqualsTestDuration + "ms");
            System.out.println("Duration with assert : " + assertTestDuration + "ms");  
    }
}

Timing is about the same for both methods:

Duration with if : 1234ms
Duration with assert : 1313ms

Disabling assertions makes very little difference:

Duration with if : 1391ms
Duration with assert : 1375ms

Have I missed any compelling reasons why null checks with if conditions are preferable to assert?

like image 327
ACHC Avatar asked May 30 '18 21:05

ACHC


People also ask

How do you assert for null?

Verifies that the object that is passed in is equal to null If the object is not null null then an AssertionException is thrown. Verifies that the object that is passed in is equal to null If the object is not null then an AssertionException is thrown.

How do you write a JUnit for null check?

If you want to check whether a String is not null, you need to use someString != null . But that does not solve your problem that it is not possible to return null from a constructor. The only thing you could do ist to throw a NullPointerException—and that is exactly what your code does.

How do you assert null in Testng?

#4) assertNullassert null is used to verify if the provided object contains a null value. It takes an object as the parameter and throws an AssertionError if the provided object does not hold a null value.

Is null in JUnit?

Assert class in case of JUnit 4 or JUnit 3 to assert using assertNull method. Assertions. assertNull() checks that object is null. In case, object is not null, it will through AssertError.


2 Answers

Ask yourself how you would handle the null cases? What do you do if an object is null that should not be. In most of the cases it absolutely ok to not handle it, at all. Just let it produce a NullPointerException sometime later in the execution. It is very likely to be a programming error, anyway, so it's ok to be caught by an ExceptionHandler eventually writing it to the logs.

Of course, there are cases when you need to react on null objects. if-else is made for such cases. It's easy, self-explaining, every programmer knows that construct, so why not using it. assert in production is discouraged, anyway. See this post on SO, for instance. And, for my taste, it's quite cumbersome with the try/catch block.

There are other options, as well. For instance, DavidW suggested to use annotations, which is perfectly fine, as long as you make sure that these annotations are interpreted (can be an issue when migrating code, for example).

Another approach are Validator classes. For instance, the Apache Commons library has a Validate class that checks for certain conditions and would throw an appropriate exception if the condition is not fullfilled. Of course, you can write your own Validators that will throw your custom exceptions, as well. You'll end up with a short concise one-liner like

Validate.notNull(myObj) 
Validate.hasEmailCorrectSyntax("[email protected]");

Also take a look at Java's Object.requireNotNull

like image 117
Jan B. Avatar answered Oct 18 '22 23:10

Jan B.


Using assert at all has to presume that the -ea flag is enabled, and in many instances...it isn't. The assert will accomplish the same thing as the null checks, with the clear side-effect that if one doesn't have their environment configured in a particular way, the code will not function as they expect.

For that reason, it makes sense to eschew assert and leverage the null checks where necessary. More concisely, if one can, it's preferable to wrap everything that could be null in an Optional instance and operate on it using ifPresent (or orElseThrow since you seem to want to indicate an error if those values are null) instead.

like image 21
Makoto Avatar answered Oct 18 '22 23:10

Makoto