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...
Related
Recently I was doing a code review and came across this guy:
if(!sharePermission.isExpired() ? activePermissions.add(sharePermission) : expiredPermissions.add(sharePermission));
Basically using a ternary expression to call methods that return a boolean value and wrapping it in an if(...) statement to satisfy the requirement of being a standalone statement. Is this more or less valid than
if(!sharePermission.isExpired())
activePermissions.add(sharePermission);
else
expiredPermissions.add(sharePermission);
if you really need to condense your code to one line? Is any sort of extra space allocated for the value returned from the ternary expression when wrapped in the if(...) ?
I'm not a fan of either of them, just curious.
It's an abuse of the if statement to do that, never mind the conditional expression.
It would be cleaner to write either a full if statement, or to use the conditional operator to select a list to add to:
List<Permission> list = isExpired() ? expiredPermission : activePermission;
list.add(sharePermission);
There is no assignment happening, only an evaluation of a boolean condition. No extra memory is allocated for the result of the evaluation.
Using a ternary expression to emulate a ternary statement, however, is grossly unorthodox. It is going to reduce readability of your code, without bringing any additional benefit. Hence, using a plain if with an else is a better alternative.
Note that if activePermissions and expiredPermissions are of the same type, you can use a ternary expression to decide between the targets of the add call, as follows:
(sharePermission.isExpired() ? expiredPermissions : activePermissions).add(sharePermission);
The ternary equivalent for the if..else that you are looking for is something like -
(!sharePermission.isExpired() ? activePermissions : expiredPermissions).add(sharePermission); // no if here
is equivalent to
if(!sharePermission.isExpired()) {
activePermissions.add(sharePermission);
}
else {
expiredPermissions.add(sharePermission);
}
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.
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.
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.
This question already has answers here:
Ternary Operator
(4 answers)
Closed 5 months ago.
Is there a way to implement this in a ternary operation. I'm very new to that ternary stuff, maybe you could guide me.
if(selection.toLowerCase().equals("produkt"))
cmdCse.setVisible(true);
else
cmdCse.setVisible(false);
This one doesn't seem to work.
selection.toLowerCase().equals("produkt")?cmdCse.setVisible(true):cmdCse.setVisible(false);
In this case, you don't even need a ternary operator:
cmdCse.setVisible(selection.toLowerCase().equals("produkt"));
Or, cleaner:
cmdCse.setVisible(selection.equalsIgnoreCase("produkt"));
Your version:
selection.toLowerCase().equals("produkt")? cmdCse.setVisible(true): cmdCse.setVisible(false);
is semantically incorrect: ternary operator should represent alternative assignments, it's not a full replacement for if statements. This is ok:
double wow = x > y? Math.sqrt(y): x;
because you are assigning either x or Math.sqrt(y) to wow, depending on a condition.
My 2cents: use ternary operator only when it makes your program clearer, otherwise you will end up having some undecipherable one-liners.
Perhaps
cmdCse.setVisible(selection.toLowerCase().equals("produkt"));
The ternary operator isn't exactly like an if statement. A ternary operator has to "return" something from both sides, so putting void method calls like setVisible() there won't work.
Instead, you could do something like this without ternary operators at all:
cmdCse.setVisible(selection.toLowerCase().equals("product"));
But just to demonstrate the point, the ternary equivalent would look something like this:
cmdCse.setVisible(selection.toLowerCase().equals("product") ? true : false);
Notice how now the ternary operator "returns" true or false on both sides instead of simply calling a void method.
I think this will work for you
cmdCse.setVisible(selection.toLowerCase().equals("produkt"));
Directly from the docs
Use the ?: operator instead of an if-then-else statement if it makes your code more readable; for example, when the expressions are compact and without side-effects (such as assignments).
In your case cmdCse.setVisible(true / false); doesn't return anything, and the operation also has side effects (it changes state of cmdCse), so the conditional operator cannot be used here (when you do use the operator, both of the ? and : branches must have the same return type).
As an aside, please note that .. ? .. : .. should be referred to as the conditional operator
On the issue of using exceptions
I want to answer the issue of the exceptions here as this question is a duplicate for another question concerning throwing exceptions from a ternary expression, but this is not addressed in the above answers.
The general consensus is that it cannot be done directly as in:
public Character next() {
return hasNext() ? s.charAt(cur++) : throw new NoSuchElementException(); // compilation error
}
will give you a compilation error, but as Clement pointed out it can be done via a declared extra function. It can also be done via (ab-)using lambda expressions.
public Character next() {
return hasNext() ? s.charAt(cur++) : ((Function<Integer, Character>) x -> {throw new NoSuchElementException();}).apply(1);
}
for sure this is not that pretty (it is pretty ugly) and I would not recommend to do that for readability purposes, but sometimes there are circumstances which might warrant exceptionally doing that. If someones figures out a way to do it without the cast it would be a bit more readable.
If you had a function throwNoSuchElementException() defined somewhere that you use more than once, it would look a bit more readable:
public Character next() {
return hasNext() ? s.charAt(cur++) : throwNoSuchElementException();
}
(P.S.: I included this answer for completeness sake, as I asked myself can it really be not done?)
(P.S.S.: If the exception to be thrown is not a runtime exception this will not work so easily and would require even more handstands - not really worth it)
Here are my tips, if you need to set things to booleans, then simple use setBoolean(condition), else, if you need to set a variable to a non boolean value, then use var=condition?result1:result2(or the variable itself if you don't want to change if condition is false), otherwise, use if else.