26

While fiddling around in Java, I initialized a new String array with a negative length. i.e. -

String[] arr = new String[-1];

To my surprise, the compiler didn't complain about it. Googling didn't bring up any relevant answers. Can anyone shed some light on this matter?

Many thanks!

Tom Teman
  • 1,975
  • 3
  • 28
  • 43
  • 1
    The compiler does not check the size of the array, but if the size of the negative throws java.lang.NegativeArraySizeException – isvforall May 17 '12 at 13:17
  • 3
    `String[] arr = new String[someNumberThatMightOrMightNotBeNegative];` - Check _that_ at compile time, I dare you! – Izkata May 17 '12 at 16:59
  • @Izkata - I did, using Eclipse, and it's still very complaisant about it (i.e - no warnings or anything) – Tom Teman May 17 '12 at 17:36
  • @TomTeman You misunderstand. The compiler would have to actually _run_ the code to figure out if the number was negative or not, and even then, it would have to try all possible code paths, including all possible inputs, to definitively determine that that number was negative or not. It is simply isn't possible. So the language designers decided to do the check at runtime, since that would catch both your version in the question and the version in my above comment. – Izkata May 17 '12 at 17:54
  • Lol..Simple answer..Switch to C# – om471987 May 17 '12 at 18:41
  • @Izkata: It's possible, just not yet done in a mainstream language. – GManNickG May 18 '12 at 03:22
  • @Izkata Yeah, I understood that from Stephen C's answer (and the difference between runtime and compile time). But since we are dealing with a primitive constant, it still seems weird that the compiler doesn't flag it down. Oh well, the code designers work in mysterious ways. – Tom Teman May 19 '12 at 18:26
  • The [error-prone](https://github.com/google/error-prone) library exists to augment Java with additional semantic sanity checks; you could contribute a negative-array-size check if one doesn't already exist. – dimo414 Nov 24 '16 at 06:51

4 Answers4

25

The reason is that the JLS allows this, and a compiler that flagged it as a compilation error would be rejecting valid Java code.

It is specified in JLS 15.10.1. Here's the relevant snippet:

"... If the value of any DimExpr expression is less than zero, then a NegativeArraySizeException is thrown."

Now if the Java compiler flagged the code as an error, then that specified behaviour could not occur ... in that specific code.

Furthermore, there's no text that I can find that "authorizes" the compiler to reject this in the "obvious mistake" cases involving compile-time constant expressions like -1. (And who is to say it really was a mistake?)


The next question, of course, is 'why does the JLS allow this?'

You've need to ask the Java designers. However I can think of some (mostly) plausible reasons:

  • This was originally overlooked, and there's no strong case for fixing it. (Noting that fixing it breaks source code compatibility.)

  • It was considered to be too unusual / edge case to be worth dealing with.

  • It would potentially cause problems for people writing source code generators. (Imagine, having to write code to evaluate compile-time constant expressions in order that you don't generate non-compilable code. With the current JLS spec, you can simply generate the code with the "bad" size, and deal with the exception (or not) if the code ever gets executed.)

  • Maybe someone had a plan to add "unarrays" to Java :-)


Other answers have suggested that the compiler could / should "flag" this case. If "flagging" means outputting a warning message, that is certainly permitted by the JLS. However, it is debatable whether the compiler should do this. On the one hand, if the above code was written by mistake, then it would be useful to have that mistake flagged. On the other hand, if it was not a mistake (or the "mistake" was not relevant) then the warning would be noise, or worse. Either way, this is something that you would need to discuss with the maintainer(s) for the respective compiler(s).

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • The next question, of course, is 'why does the JLS allow this?' – Tony Ennis May 17 '12 at 13:16
  • @TonyEnnis: It allows it in the sense that it doesn't say anything about it either way; see http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.10. – Oliver Charlesworth May 17 '12 at 13:17
  • 1
    It is not true that the specified behaviour could not occur just because a negative compile-time constant was not allowed for `DimExpr`. – Marko Topolnik May 17 '12 at 13:31
  • @MarkoTopolnik - that is true. But there would also need to be some text in the JLS that says this case WAS an invalid program ... as distinct from a program that throws an exception. – Stephen C May 17 '12 at 13:39
  • And you are ignoring the statement immediately after it that deals explicitly with the point you are disputing. – Stephen C May 17 '12 at 13:47
  • I don't understand what you are saying, or I do understand it and I disagree. Either way, I don't think this is going anywhere ... – Stephen C May 17 '12 at 13:57
  • It was supposed to be a minor point anyway. You should delete that first part of your answer since it is a *non-sequitur* and leave the rest of your otherwise very good answer as it stands. – Marko Topolnik May 17 '12 at 14:02
  • 1
    @MarkoTopolnik - your comment is noted, but I disagree. – Stephen C May 17 '12 at 14:11
  • 1
    Do you then claim that the **only way** for the "specified behavior" at hand to occur is when executing `new String[]`? Because code like `int i = -1; new String[i];` is already outside of the realm of compile-time constants. – Marko Topolnik May 17 '12 at 14:14
  • 1
    No I don't. I claim that if `new String[-1]` was flagged as a compilation error, then `new String[-1]` could not throw an exception. The JLS states that it *should* throw an exception ... without any qualification about compile time constant expressions. That is MY interpretation of the JLS. Anyway, this is a silly quibble because it is a FACT that this is NOT a compilation error, and nothing in the JLS says that it should be a compilation error. – Stephen C May 24 '12 at 01:51
2

I see no reason why this couldn't be flagged up at compile time (at least as a warning), since this unconditionally throws NegativeArraySizeException when executed.

I've done some quick experiments with my compiler, and it seems surprisingly relaxed about this sort of thing. It issues no warning about integer divide by zero in constant expressions, out-of-bounds array access with constant indices etc.

From this I conclude that the general pattern here is to trust the programmer.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • Also, check Pau's 1st block code, it makes sense why not to have restriction over '-1' size of array at compile-time or run-time(here I mean passing -1 value, it will then raise exception) – Nandkumar Tekale May 17 '12 at 14:02
1

Compiler only responsible for checking language syntax, but not the semantic meaning of you code. Thus it is reasonable the compiler is not complaining error as there is no syntax error in your code at all.

In Java, array is allocated at runtime, which is absolutely ok. If it is allocate at compile time, then how compiler check the following code?

// runtime pass the length, with any value
void t(int length) {
   String[] stirngs = new String[length];
}

When pass negative value as length to contruct array, the runtime exception will being thrown.

public class Main {

    public static void main(String[] args) {
        String[] v = new String[-1];
    }
}

with error:

Exception in thread "main" java.lang.NegativeArraySizeException
    at Main.main(Main.java:5)
Pau Kiat Wee
  • 9,485
  • 42
  • 40
  • 2
    And what about dead code detection? Is that syntax or semantics? Dead code is a compiler error. There are a number of other such features in Java, like checking that each code path leads to a return statement. – Marko Topolnik May 17 '12 at 13:39
  • Method without return surely will detected by compiler, but not some semantic dead code like ` if(true) { System.out.println("true"); } else { System.out.println("dead code"); }`. Only IDE will flag as warning. – Pau Kiat Wee May 17 '12 at 13:47
  • But method with two returns and a third one missing -- that's semantic dead code, too. Otherwise it would have been eliminated by the CFG, not by a complex dead code detection algorithm. Static analysis is NOT syntax checking. Neither is type checking, or checking the validity of method calls, etc. There's a lot of semantic checking done by the Java compiler, as per JLS. – Marko Topolnik May 17 '12 at 13:52
  • 2
    @PauKiatWee : this is wrong "Compiler only responsible for checking language syntax, but not the semantic meaning of you code.". Check compiler phases here http://www.mec.ac.in/resources/notes/notes/compiler/Module1/intro.html – Nandkumar Tekale May 17 '12 at 13:58
0

Java compiler takes an integer as the length of an array. It can be a variable or a compile-time constant. The length of an array is established when the array is created. After creation, its length is fixed.

The compiler should flag a negative compile-time constant as the length of an array. It just does not do so . If the length is a negative number you will get a NegativeArraySizeException at run time.

Don Li
  • 1,095
  • 2
  • 12
  • 17
  • "The compiler should flag a negative compile-time constant as the length of an array" is inaccurate per @Stephen C's answer. To do so would violate the JLS. – Redwood May 23 '12 at 23:10
  • @LawrenceJohnston : What I mean is "The compiler does not flag a negative compile-time constant as the length of an array.It should flag it since it's easy for the compiler to implement the check" – Don Li May 24 '12 at 00:24