70

I tried this and get weird behavior from JAVA, can someone explain this for me?

boolean testNull(String... string) {
    if(string == null) {
        return true;
    } else {
        System.out.println(string.getClass());
        return false;
    }
}

boolean callTestNull(String s) {
    return testNull(s);
}

Then I have test case:

    @Test
    public void test_cases() {
        assertTrue(instance.testNull(null)); // NULL
        assertFalse(instance.testNull()); // NOT NULL
        assertFalse(instance.callTestNull(null)); // NOT NULL
    }

The question is if I call testNull() directly with parameter null, I will get true back, but if call callTestNull() with null, which calls testNull(), it tells me the parameter is not null, but empty array.

3
  • How do you find that array is empty? Commented Jul 17, 2013 at 14:41
  • 5
    I meant in terms of Java terminology. But yes, the character "..." is indeed called ellipsis. More info on programming use here en.wikipedia.org/wiki/Ellipsis_(programming_operator) Commented Jul 17, 2013 at 15:02
  • Possible duplicate of Java, 3 dots in parameters Commented Jun 14, 2016 at 3:39

1 Answer 1

75

The question is if I call testNull() directly with parameter null, I will get true back, but if call callTestNull() with null, which calls testNull(), it tells me the parameter is not null, but empty array.

Yes. If you call it with an argument with a compile-time type of String, the compiler knows that can't be a String[], so it wraps it within a string array. So this:

String x = null;
testNull(x);

is equivalent to:

String x = null;
testNull(new String[] { x });

At this point, the (misleadingly-named) string parameter will have a non-null value - instead, it will refer to an array of size 1 whose sole element is a null reference.

However, when you use the null literal directly in the method call, that's directly convertible to String[], so no wrapping is performed.

From JLS section 15.12.4.2:

If the method being invoked is a variable arity method m, it necessarily has n > 0 formal parameters. The final formal parameter of m necessarily has type T[] for some T, and m is necessarily being invoked with k ≥ 0 actual argument expressions.

If m is being invoked with k ≠ n actual argument expressions, or, if m is being invoked with k = n actual argument expressions and the type of the k'th argument expression is not assignment compatible with T[], then the argument list (e1, ..., en-1, en, ..., ek) is evaluated as if it were written as (e1, ..., en-1, new |T[]| { en, ..., ek }), where |T[]| denotes the erasure (§4.6) of T[].

(Emphasis mine.)

The bit I've emphasized is why the wrapping only happens when the compile-time type of the argument is String, not the null type.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.