When is an unassigned expression a valid statement? - java

I've read Oracle's expressions tutorial and couldn't understand this.
It is well known that the following line of code is valid Java syntax:
new Object();
However, when I try this with a primitive expression:
(3 + 2);
Eclipse is showing a compile error of "The left-hand side of an assignment must be a variable".
This is true not only for primitives, but also for String literals:
"arbitraryString";
So what is the rule for an unassigned expression to be valid as a Java line of code?

The rule is in the Java Language Specification:
Certain kinds of expressions may be used as statements by following them with semicolons.
ExpressionStatement:
StatementExpression ;
StatementExpression:
Assignment
PreIncrementExpression
PreDecrementExpression
PostIncrementExpression
PostDecrementExpression
MethodInvocation
ClassInstanceCreationExpression
You see that a constructor invocation is a statement. But a String literal or mathematical expression is not.

Creating an object or calling or method can have side effects, I think this is the main reason for this, whereas nothing will ever happen with an arithmetic expression.

Line containing only
new Object();
or to be more precise
new SomeClass();
is acceptable, because code of SomeClass() constructor may be all we want.
But in case of lines containing only
"foo";
or
2;//or (2+3);
compiler knows that beside creating/reusing String literal or integer literal this code doesn't do anything else, which means it is probably some kind of programmer mistake so compiler can't accept it.

You're looking for the difference between expressions and expression-statements. Statements like myVoid(); can be written as a statement: these are void methods, etc. (that's the part you know). Expressions, like (3 + 2); and "arbitraryString", have no side-effects. They can only be treated as a value, as no code is executed. Expression-statements, like new Object(); can have side-effects and execute code, and you sometimes just want this code to be executed and ignore the returned value. The compiler therefore allows this.

Related

Not a statetment (Compiler Error Java/Android)

I am trying to do a simple if Statement using the ? pattern. Resulting in an "Not a statement"- Error. Can someone please explain to me why this is not happening using a normal if statement?
Error:
cursor.isNull(0) ? insert_SQL_RSServer.bindNull(0) : insert_SQL_RSServer.bindLong(0, cursor.getLong(0)); // id
No Error:
if(cursor.isNull(0))
insert_SQL_RSServer.bindNull(0);
else
insert_SQL_RSServer.bindLong(0, cursor.getLong(0));
This is completely the same behavior ....
The ternary conditional operator is an expression, and it must have a return type, which is determined by the types of the 2nd and 3rd operands.
Therefore, if your bindNull() and bindLong() methods have void return type, they can't be used in this operator.
In Java, an expression is not a statement except in the case of the following:
StatementExpression:
Assignment
PreIncrementExpression
PreDecrementExpression
PostIncrementExpression
PostDecrementExpression
MethodInvocation
ClassInstanceCreationExpression
Reference: JLS 14.8.
A ternary expression is not one of the above.
Thanks! But this is still bullshit... However..
It is the way that it is. This is how Java is specified.
This could simply be a design choice that reflected the language designers' personal taste / views on simplicity. Alternatively, there could be a deeper reason or reasons for the choice; e.g. it might have solved some issue with ambiguous parses.

Syntax with missed Expression for basic for-loop

Some days ago I was talking with my colleagues about this code in Java:
for( ; ; ) { }
Nothing special here, just an infinite loop.
But we wonder why this is syntactically correct. If you take a look to JLS §14.14.1 you'll see this:
for ( [ForInit] ; [Expression] ; [ForUpdate] ) Statement
I understand that ForInit and ForUpdate can be omitted. But at least I would expect that Expression is mandatory, like in while-loop:
while() {} // compile error, Expression is missed
So why can Expression be omitted on a for-loop? And even one think more - why is missed Expression resolved to true? My expectation would be that empty Expression is resolved to false.
The same think is valid for other languages (I've try it with C and JavaScript, but I believe every language with for-loops behaves in that way).
Why is an Expression clause not mandatory in for-loop (but in while-loop)? Why does empty Expression resolve to true and not to false?
The rationale starts in JLS 14.14.1.1 and continues into 14.14.1.2, emphasis mine.
If the ForInit part is not present, no action is taken.
If the Expression is not present, or it is present and the value resulting from its evaluation (including any possible unboxing) is true, then the contained Statement is executed...
The JLS permits the blank ForInit, Expression and ForUpdate statements and has conditions to deal with their absence, so omitting them is acceptable.
It is not permissible to do so with while loops, per JLS 14.12.
The Expression must have type boolean or Boolean, or a compile-time error occurs.
From this, the specification is not permitting a blank expression to be passed through, since that would result in a compile-time error per above.
If you're looking for a slightly more historical reason, the C specification mandates this as well.
Since Java took heavy inspiration from C (and is mostly implemented in it), it makes perfect sense for Java's loops to behave similarly to C's loops, and this is how they behave: expressions are optional in C's for statement, and mandatory in its while statement.

Replacing an if statement with a disjunction

Just for fun, I was trying to replace:
if (set1.add(x) == false)
{
set2.add(x);
}
with:
set1.add(x) || set2.add(x);
However, Eclipse complains:
Syntax error on token "||", invalid AssignmentOperator
The left-hand side of an assignment must be a variable
Could anybody shine some light onto these error messages? They don't make much sense to me.
As #qqilihq said in the comments try to do
boolean temp = set1.add(x) || set2.add(x);
or more awkward:
if(set1.add(x) || set2.add(x));
According to documentation java statements which can end with a semicolon are:
Assignment expressions
Any use of ++ or --
Method invocations
Object creation expressions
What you've written is not a statement it's an expression. Here you can find more about statements and expressions. So simple but worth to look.
There are a number of answers far, but I agree with Bohemian's answer that the most straightforward simplification (although it doesn't use ||) is this:
if ( !set1.add(x) ) set2.add(x);
That doesn't explain the error message though. Mustafa Genç comes closer on this, but I think it's worthwhile to look at the language specification here. exp1 || exp2 is an expression, and the problem here is that you're trying to use it in a context where a statement is expected. According to 14.8. Expression Statements, some kinds of expressions can be used where statements are expected by attaching a semicolon:
14.8. Expression Statements
Certain kinds of expressions may be used as statements by following
them with semicolons.
ExpressionStatement:
StatementExpression ;
StatementExpression:
Assignment
PreIncrementExpression
PreDecrementExpression
PostIncrementExpression
PostDecrementExpression
MethodInvocation
ClassInstanceCreationExpression
An expression statement is executed by evaluating the expression; if
the expression has a value, the value is discarded.
The reason that you can't do what you're trying to do, though, is that not every expression can be used as a statement. However, it does discuss some ways to work around this. From the same section of the specification (emphasis added):
Unlike C and C++, the Java programming language allows only certain
forms of expressions to be used as expression statements. Note that
the Java programming language does not allow a "cast to void" - void
is not a type - so the traditional C trick of writing an expression
statement such as:
(void)... ; // incorrect!
does not work. On the other hand, the Java
programming language allows all the most useful kinds of expressions
in expressions statements, and it does not require a method invocation
used as an expression statement to invoke a void method, so such a
trick is almost never needed. If a trick is needed, either an
assignment statement (§15.26) or a local variable declaration
statement (§14.4) can be used instead.
This approach is what the first snipped in Reik Val's answer is using:
boolean temp = set1.add(x) || set2.add(x);
I would just:
if (!set1.add(x))
set2.add(x);
The statement
boolean temp = set1.add(x) || set2.add(x);
and any variation thereof is dangerous. You'll hardly ever know what happens there. Note that the right expression is NOT evaludated iff the first expression is true. That is, the attempt to add it to set2 will only be made if it was not yet contained in set1.
EDIT: Now, reading the question again, it seems that this was exactly what you intended. So I think that the anser https://stackoverflow.com/a/21755051 by Mustafa Genç is the relevant here
Usually, you should write clearly what you want to do
boolean wasNotContainedInSet1 = set1.add(x);
boolean wasNotContainedInSet2 = set2.add(x);
boolean wasNotContainedInAnySet =
wasNotContainedInSet1 | wasNotContainedInSet2;
or
boolean wasNotContainedInSet1 = set1.add(x);
if (!wasNotContainedInSet1) {
set2.add(x);
}
or whatever...

Statements inside ?: expression

I'm learning scala and trying to understand the following sentence:
In Java you can't put statements inside a ?: expression
Can someone explain this to me, perhaps with an example and maybe in the context of Scala?
Java has a ternary conditional operator inherited from C, it looks like this:
int x = some_condition ? 1 : 2;
x will be equal to 1 if some_condition is true, and to 2 otherwise. Java requires that arguments to this operator are expressions, i.e. things which result in concrete values. For example, method call or constant literal are expressions, but a loop or a conditional statement or a variable definition are not expressions because they do not have meaningful value. This means that you cannot return, say, variable definition from a function, but you can return result of method call.
Scala does not have ternary operator. But it does not need one because in Scala everything is expression. Even loops - they result in a special value of Unit type. Conditionals are also expressions, they return a value of common supertype of all branches. Because of this you can use plain conditional "statement" instead of ternary operator. This Scala snippet is equivalent to Java one above:
val x = if (some_condition) 1 else 2
Moreover, in Scala every block is an expression too (its value is the value of the last line in the block), so you can have statements, for example assignments, inside the "ternary operator":
val x = if (some_condition) {
val y = some_computation()
y*2
} else {
val z = another_computation()
z + 3
}
More generally, you can't put arbitrary statements in any expression, not just the conditional expression.
A method's block is a list of statements. A statement is made up of other statements and/or expressions. But expressions, being the building blocks of statements, do normally not contain statements.
Well, there is one exception: a class creation expression of the form
new C(argument list) { class definition }
This creates at compile time a new class that is a subclass of C and at runtime an instance of that class. Hence it would be possible to write something like:
cond ? (new Object() {
public int get() { System.out.println("Hi"); return 42; }
}).get()
: 0
to smuggle a statement into an expression.
The thing you put inside the ?: expression are other expressions. The first one must evaluate to a boolean, and the second and third evaluate to the same type (int, String, etc.). A statement is something that is executed, an expression is something that results in a value. It gets confusing because you can put executable stuff inside an expression.

Why must we use double colons for method references?

For instance why can I write the line
Character[] c = Arrays.sort(list.toArray(new Character[list.size()]))
But in documentation when I read about method referencing, they tell me to use :: instead? Doesn't it do the same as the . operator?
I dont know if the above code compiles, as I'm typing this on my mobile. Consider it a loose example.
The double colon operator is a new operator provided in Java8. It is syntactic sugar that tells the compiler to generate a lambda based on context which will call the method. This makes some lambda expression things a bit easier. Prior to Java8 this operator doesn't exist, and no, its not the same as the dot(.) operator. For example:
Math.max(4, 6) // Calls Math.max with the arguments 4 and 6
Math::max // A reference to the max method in the java.lang.Math class
For a bit of extra reading (Although this stuff is all in Beta and has not been officially released) try http://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

Categories

Resources