Why is a Java array index expression evaluated before checking if the array reference expression is null?
According to the JLS, runtime evaluation of an array access expression behaves as follows:
- First, the array reference expression is evaluated. If this
evaluation completes abruptly, then the array access completes
abruptly for the same reason and the index expression is not
evaluated. - Otherwise, the index expression is evaluated. If this
evaluation completes abruptly, then the array access completes
abruptly for the same reason. - Otherwise, if the value of the array
reference expression is null, then a NullPointerException is thrown.
So this code will print: java.lang.NullPointerException, index=2
class Test3 {
public static void main(String args) {
int index = 1;
try {
nada()[index = 2]++;
} catch (Exception e) {
System.out.println(e + ", index=" + index);
}
}
static int nada() {
return null;
}
}
The question is: for what reason do we need to first evaluate the index = 2
expression and not just throw the NullPointerException once the array reference is evaluated to null? Or in other words - why is the order 1,2,3 and not 1,3,2?
java language-lawyer
New contributor
|
show 1 more comment
According to the JLS, runtime evaluation of an array access expression behaves as follows:
- First, the array reference expression is evaluated. If this
evaluation completes abruptly, then the array access completes
abruptly for the same reason and the index expression is not
evaluated. - Otherwise, the index expression is evaluated. If this
evaluation completes abruptly, then the array access completes
abruptly for the same reason. - Otherwise, if the value of the array
reference expression is null, then a NullPointerException is thrown.
So this code will print: java.lang.NullPointerException, index=2
class Test3 {
public static void main(String args) {
int index = 1;
try {
nada()[index = 2]++;
} catch (Exception e) {
System.out.println(e + ", index=" + index);
}
}
static int nada() {
return null;
}
}
The question is: for what reason do we need to first evaluate the index = 2
expression and not just throw the NullPointerException once the array reference is evaluated to null? Or in other words - why is the order 1,2,3 and not 1,3,2?
java language-lawyer
New contributor
1
Firstly you have to initialize an array and secondly the priority of equals sign is high that's why its given null pointer exception.
– Ammar Ali
11 hours ago
5
Asking on SO why the JLS is written the way it is will not give you any good answer unless it maybe comes from one of the designers of the Java language.
– Seelenvirtuose
11 hours ago
4
They had to choose something, and both options can produce "unexpected" scenarios. (I.e. scenarios that behave in a not very intuitive way). The option that was chosen seems to be more in line with how expression evaluation works in other parts of Java.
– biziclop
11 hours ago
1
Possible duplicate of What are the rules for evaluation order in Java?
– fantaghirocco
9 hours ago
2
… which in turn is a duplicate of Is the array index or the assigned value evaluated first?
– fantaghirocco
9 hours ago
|
show 1 more comment
According to the JLS, runtime evaluation of an array access expression behaves as follows:
- First, the array reference expression is evaluated. If this
evaluation completes abruptly, then the array access completes
abruptly for the same reason and the index expression is not
evaluated. - Otherwise, the index expression is evaluated. If this
evaluation completes abruptly, then the array access completes
abruptly for the same reason. - Otherwise, if the value of the array
reference expression is null, then a NullPointerException is thrown.
So this code will print: java.lang.NullPointerException, index=2
class Test3 {
public static void main(String args) {
int index = 1;
try {
nada()[index = 2]++;
} catch (Exception e) {
System.out.println(e + ", index=" + index);
}
}
static int nada() {
return null;
}
}
The question is: for what reason do we need to first evaluate the index = 2
expression and not just throw the NullPointerException once the array reference is evaluated to null? Or in other words - why is the order 1,2,3 and not 1,3,2?
java language-lawyer
New contributor
According to the JLS, runtime evaluation of an array access expression behaves as follows:
- First, the array reference expression is evaluated. If this
evaluation completes abruptly, then the array access completes
abruptly for the same reason and the index expression is not
evaluated. - Otherwise, the index expression is evaluated. If this
evaluation completes abruptly, then the array access completes
abruptly for the same reason. - Otherwise, if the value of the array
reference expression is null, then a NullPointerException is thrown.
So this code will print: java.lang.NullPointerException, index=2
class Test3 {
public static void main(String args) {
int index = 1;
try {
nada()[index = 2]++;
} catch (Exception e) {
System.out.println(e + ", index=" + index);
}
}
static int nada() {
return null;
}
}
The question is: for what reason do we need to first evaluate the index = 2
expression and not just throw the NullPointerException once the array reference is evaluated to null? Or in other words - why is the order 1,2,3 and not 1,3,2?
java language-lawyer
java language-lawyer
New contributor
New contributor
edited 6 hours ago
senseiwu
1,99911333
1,99911333
New contributor
asked 11 hours ago
Andrei NepshaAndrei Nepsha
1269
1269
New contributor
New contributor
1
Firstly you have to initialize an array and secondly the priority of equals sign is high that's why its given null pointer exception.
– Ammar Ali
11 hours ago
5
Asking on SO why the JLS is written the way it is will not give you any good answer unless it maybe comes from one of the designers of the Java language.
– Seelenvirtuose
11 hours ago
4
They had to choose something, and both options can produce "unexpected" scenarios. (I.e. scenarios that behave in a not very intuitive way). The option that was chosen seems to be more in line with how expression evaluation works in other parts of Java.
– biziclop
11 hours ago
1
Possible duplicate of What are the rules for evaluation order in Java?
– fantaghirocco
9 hours ago
2
… which in turn is a duplicate of Is the array index or the assigned value evaluated first?
– fantaghirocco
9 hours ago
|
show 1 more comment
1
Firstly you have to initialize an array and secondly the priority of equals sign is high that's why its given null pointer exception.
– Ammar Ali
11 hours ago
5
Asking on SO why the JLS is written the way it is will not give you any good answer unless it maybe comes from one of the designers of the Java language.
– Seelenvirtuose
11 hours ago
4
They had to choose something, and both options can produce "unexpected" scenarios. (I.e. scenarios that behave in a not very intuitive way). The option that was chosen seems to be more in line with how expression evaluation works in other parts of Java.
– biziclop
11 hours ago
1
Possible duplicate of What are the rules for evaluation order in Java?
– fantaghirocco
9 hours ago
2
… which in turn is a duplicate of Is the array index or the assigned value evaluated first?
– fantaghirocco
9 hours ago
1
1
Firstly you have to initialize an array and secondly the priority of equals sign is high that's why its given null pointer exception.
– Ammar Ali
11 hours ago
Firstly you have to initialize an array and secondly the priority of equals sign is high that's why its given null pointer exception.
– Ammar Ali
11 hours ago
5
5
Asking on SO why the JLS is written the way it is will not give you any good answer unless it maybe comes from one of the designers of the Java language.
– Seelenvirtuose
11 hours ago
Asking on SO why the JLS is written the way it is will not give you any good answer unless it maybe comes from one of the designers of the Java language.
– Seelenvirtuose
11 hours ago
4
4
They had to choose something, and both options can produce "unexpected" scenarios. (I.e. scenarios that behave in a not very intuitive way). The option that was chosen seems to be more in line with how expression evaluation works in other parts of Java.
– biziclop
11 hours ago
They had to choose something, and both options can produce "unexpected" scenarios. (I.e. scenarios that behave in a not very intuitive way). The option that was chosen seems to be more in line with how expression evaluation works in other parts of Java.
– biziclop
11 hours ago
1
1
Possible duplicate of What are the rules for evaluation order in Java?
– fantaghirocco
9 hours ago
Possible duplicate of What are the rules for evaluation order in Java?
– fantaghirocco
9 hours ago
2
2
… which in turn is a duplicate of Is the array index or the assigned value evaluated first?
– fantaghirocco
9 hours ago
… which in turn is a duplicate of Is the array index or the assigned value evaluated first?
– fantaghirocco
9 hours ago
|
show 1 more comment
4 Answers
4
active
oldest
votes
An array access expression has two sub-expressions:
An array access expression contains two subexpressions, the array reference expression (before the left bracket) and the index expression (within the brackets).
The two sub-expressions are evaluated before the array access expression itself, in order to evaluate the expression.
After evaluating the two sub-expressions
nada()[index = 2]++;
becomes
null[2]++;
Only now the expression is evaluated and the NullPointerException
is thrown.
This is consistent with the evaluation of most expressions in Java (the only counter examples I can think of are short circuiting operators such as && and ||).
For example, if you make the following method call:
firstMethod().secondMethod(i = 2);
First you evaluate firstMethod()
and i = 2
, and only later you throw NullPointerException
if firstMethod()
evaluated to null
.
add a comment |
This is because in the generated bytecode there are no explicit null checks.
nada()[index = 2]++;
is translated into the following byte code:
// evaluate the array reference expression
INVOKESTATIC Test3.nada ()[I
// evaluate the index expression
ICONST_2
DUP
ISTORE 1
// access the array
// if the array reference expression was null, the IALOAD operation will throw a null pointer exception
DUP2
IALOAD
ICONST_1
IADD
IASTORE
add a comment |
The decision may be partially be rooted in performance.
In order to know that index = 2
is not going to be required, we would have to first evaluate nada()
and then check whether it was null. We would then branch on the result of this condition, and decide whether or not to evaluate the array index expression.
Every perfectly valid array index expression would be made slower by one additional operation, just for the sake of saving code - code that is going to throw an exception anyway - from evaluating one expression unnecessarily.
It is an optimistic approach which works better in the majority of cases.
add a comment |
The basic byte code operations are (for an int
)
ALOAD array_address
ILOAD index
IALOAD array_element_retrieval
The IALOAD does the null pointer check. In reality the code is a bit more elaborate:
- calculate array address
- calculate index
- IALOAD
So the answer is: it would need an extra checking operation after the array address is loaded, in anticipation of the array access.
Behavior by straight implementation.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Andrei Nepsha is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55160799%2fwhy-is-a-java-array-index-expression-evaluated-before-checking-if-the-array-refe%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
An array access expression has two sub-expressions:
An array access expression contains two subexpressions, the array reference expression (before the left bracket) and the index expression (within the brackets).
The two sub-expressions are evaluated before the array access expression itself, in order to evaluate the expression.
After evaluating the two sub-expressions
nada()[index = 2]++;
becomes
null[2]++;
Only now the expression is evaluated and the NullPointerException
is thrown.
This is consistent with the evaluation of most expressions in Java (the only counter examples I can think of are short circuiting operators such as && and ||).
For example, if you make the following method call:
firstMethod().secondMethod(i = 2);
First you evaluate firstMethod()
and i = 2
, and only later you throw NullPointerException
if firstMethod()
evaluated to null
.
add a comment |
An array access expression has two sub-expressions:
An array access expression contains two subexpressions, the array reference expression (before the left bracket) and the index expression (within the brackets).
The two sub-expressions are evaluated before the array access expression itself, in order to evaluate the expression.
After evaluating the two sub-expressions
nada()[index = 2]++;
becomes
null[2]++;
Only now the expression is evaluated and the NullPointerException
is thrown.
This is consistent with the evaluation of most expressions in Java (the only counter examples I can think of are short circuiting operators such as && and ||).
For example, if you make the following method call:
firstMethod().secondMethod(i = 2);
First you evaluate firstMethod()
and i = 2
, and only later you throw NullPointerException
if firstMethod()
evaluated to null
.
add a comment |
An array access expression has two sub-expressions:
An array access expression contains two subexpressions, the array reference expression (before the left bracket) and the index expression (within the brackets).
The two sub-expressions are evaluated before the array access expression itself, in order to evaluate the expression.
After evaluating the two sub-expressions
nada()[index = 2]++;
becomes
null[2]++;
Only now the expression is evaluated and the NullPointerException
is thrown.
This is consistent with the evaluation of most expressions in Java (the only counter examples I can think of are short circuiting operators such as && and ||).
For example, if you make the following method call:
firstMethod().secondMethod(i = 2);
First you evaluate firstMethod()
and i = 2
, and only later you throw NullPointerException
if firstMethod()
evaluated to null
.
An array access expression has two sub-expressions:
An array access expression contains two subexpressions, the array reference expression (before the left bracket) and the index expression (within the brackets).
The two sub-expressions are evaluated before the array access expression itself, in order to evaluate the expression.
After evaluating the two sub-expressions
nada()[index = 2]++;
becomes
null[2]++;
Only now the expression is evaluated and the NullPointerException
is thrown.
This is consistent with the evaluation of most expressions in Java (the only counter examples I can think of are short circuiting operators such as && and ||).
For example, if you make the following method call:
firstMethod().secondMethod(i = 2);
First you evaluate firstMethod()
and i = 2
, and only later you throw NullPointerException
if firstMethod()
evaluated to null
.
answered 11 hours ago
EranEran
288k37471561
288k37471561
add a comment |
add a comment |
This is because in the generated bytecode there are no explicit null checks.
nada()[index = 2]++;
is translated into the following byte code:
// evaluate the array reference expression
INVOKESTATIC Test3.nada ()[I
// evaluate the index expression
ICONST_2
DUP
ISTORE 1
// access the array
// if the array reference expression was null, the IALOAD operation will throw a null pointer exception
DUP2
IALOAD
ICONST_1
IADD
IASTORE
add a comment |
This is because in the generated bytecode there are no explicit null checks.
nada()[index = 2]++;
is translated into the following byte code:
// evaluate the array reference expression
INVOKESTATIC Test3.nada ()[I
// evaluate the index expression
ICONST_2
DUP
ISTORE 1
// access the array
// if the array reference expression was null, the IALOAD operation will throw a null pointer exception
DUP2
IALOAD
ICONST_1
IADD
IASTORE
add a comment |
This is because in the generated bytecode there are no explicit null checks.
nada()[index = 2]++;
is translated into the following byte code:
// evaluate the array reference expression
INVOKESTATIC Test3.nada ()[I
// evaluate the index expression
ICONST_2
DUP
ISTORE 1
// access the array
// if the array reference expression was null, the IALOAD operation will throw a null pointer exception
DUP2
IALOAD
ICONST_1
IADD
IASTORE
This is because in the generated bytecode there are no explicit null checks.
nada()[index = 2]++;
is translated into the following byte code:
// evaluate the array reference expression
INVOKESTATIC Test3.nada ()[I
// evaluate the index expression
ICONST_2
DUP
ISTORE 1
// access the array
// if the array reference expression was null, the IALOAD operation will throw a null pointer exception
DUP2
IALOAD
ICONST_1
IADD
IASTORE
answered 11 hours ago
Thomas KlägerThomas Kläger
6,8132818
6,8132818
add a comment |
add a comment |
The decision may be partially be rooted in performance.
In order to know that index = 2
is not going to be required, we would have to first evaluate nada()
and then check whether it was null. We would then branch on the result of this condition, and decide whether or not to evaluate the array index expression.
Every perfectly valid array index expression would be made slower by one additional operation, just for the sake of saving code - code that is going to throw an exception anyway - from evaluating one expression unnecessarily.
It is an optimistic approach which works better in the majority of cases.
add a comment |
The decision may be partially be rooted in performance.
In order to know that index = 2
is not going to be required, we would have to first evaluate nada()
and then check whether it was null. We would then branch on the result of this condition, and decide whether or not to evaluate the array index expression.
Every perfectly valid array index expression would be made slower by one additional operation, just for the sake of saving code - code that is going to throw an exception anyway - from evaluating one expression unnecessarily.
It is an optimistic approach which works better in the majority of cases.
add a comment |
The decision may be partially be rooted in performance.
In order to know that index = 2
is not going to be required, we would have to first evaluate nada()
and then check whether it was null. We would then branch on the result of this condition, and decide whether or not to evaluate the array index expression.
Every perfectly valid array index expression would be made slower by one additional operation, just for the sake of saving code - code that is going to throw an exception anyway - from evaluating one expression unnecessarily.
It is an optimistic approach which works better in the majority of cases.
The decision may be partially be rooted in performance.
In order to know that index = 2
is not going to be required, we would have to first evaluate nada()
and then check whether it was null. We would then branch on the result of this condition, and decide whether or not to evaluate the array index expression.
Every perfectly valid array index expression would be made slower by one additional operation, just for the sake of saving code - code that is going to throw an exception anyway - from evaluating one expression unnecessarily.
It is an optimistic approach which works better in the majority of cases.
answered 10 hours ago
MichaelMichael
21k83472
21k83472
add a comment |
add a comment |
The basic byte code operations are (for an int
)
ALOAD array_address
ILOAD index
IALOAD array_element_retrieval
The IALOAD does the null pointer check. In reality the code is a bit more elaborate:
- calculate array address
- calculate index
- IALOAD
So the answer is: it would need an extra checking operation after the array address is loaded, in anticipation of the array access.
Behavior by straight implementation.
add a comment |
The basic byte code operations are (for an int
)
ALOAD array_address
ILOAD index
IALOAD array_element_retrieval
The IALOAD does the null pointer check. In reality the code is a bit more elaborate:
- calculate array address
- calculate index
- IALOAD
So the answer is: it would need an extra checking operation after the array address is loaded, in anticipation of the array access.
Behavior by straight implementation.
add a comment |
The basic byte code operations are (for an int
)
ALOAD array_address
ILOAD index
IALOAD array_element_retrieval
The IALOAD does the null pointer check. In reality the code is a bit more elaborate:
- calculate array address
- calculate index
- IALOAD
So the answer is: it would need an extra checking operation after the array address is loaded, in anticipation of the array access.
Behavior by straight implementation.
The basic byte code operations are (for an int
)
ALOAD array_address
ILOAD index
IALOAD array_element_retrieval
The IALOAD does the null pointer check. In reality the code is a bit more elaborate:
- calculate array address
- calculate index
- IALOAD
So the answer is: it would need an extra checking operation after the array address is loaded, in anticipation of the array access.
Behavior by straight implementation.
answered 11 hours ago
Joop EggenJoop Eggen
78.1k755105
78.1k755105
add a comment |
add a comment |
Andrei Nepsha is a new contributor. Be nice, and check out our Code of Conduct.
Andrei Nepsha is a new contributor. Be nice, and check out our Code of Conduct.
Andrei Nepsha is a new contributor. Be nice, and check out our Code of Conduct.
Andrei Nepsha is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55160799%2fwhy-is-a-java-array-index-expression-evaluated-before-checking-if-the-array-refe%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Firstly you have to initialize an array and secondly the priority of equals sign is high that's why its given null pointer exception.
– Ammar Ali
11 hours ago
5
Asking on SO why the JLS is written the way it is will not give you any good answer unless it maybe comes from one of the designers of the Java language.
– Seelenvirtuose
11 hours ago
4
They had to choose something, and both options can produce "unexpected" scenarios. (I.e. scenarios that behave in a not very intuitive way). The option that was chosen seems to be more in line with how expression evaluation works in other parts of Java.
– biziclop
11 hours ago
1
Possible duplicate of What are the rules for evaluation order in Java?
– fantaghirocco
9 hours ago
2
… which in turn is a duplicate of Is the array index or the assigned value evaluated first?
– fantaghirocco
9 hours ago