TernaryOperator (? :) for functions Java. How close we can get? [duplicate] - java

This question already has answers here:
Java: Ternary with no return. (For method calling)
(6 answers)
Closed 4 years ago.
Java has ternary operator, that works on variables:
(a > 0) ? b++ : c--;
What is a, b, c were functions? I tested something like (a returns boolean, b & c are void):
a() ? b() : c();
but even my Eclipse does not allow that.
How close could I get to this programmatically (to generate functionality to make this with minimum amount of lines)?
I know in other languages like Javascript I could just pass function as parameter, but I have not met similar in Java.
Edit
We have gone in discussion to sidewals because of bad constellation of question, but here is what I want, and it is a real world problem:
What I want to achieve is single-liner to call second or third function based on return value of the first.
With minimum amount of code of course.
What I had tried was that ternary that is made to other things, that I know now.

As others have already explained, the conditional operator is an expression that evaluates to a value, and can thus not be applied to void methods.
If you need a one-liner discarding any return values, use a simple if-else:
if (a()) b(); else c();

If you go through Java Ternary Operator let's you assign a value to a variable based on a boolean expression — either a boolean field, or a statement that evaluates to a boolean result (Its used for assignment). In above you are trying to call functions with return value void that is not allowed in Ternary Operator in java.
The ternary operator, also known as the conditional operator, can be
used as an alternative to the Java if/then/else syntax

You can only use the ternary operator as an expression, not a statement. It's not simply alternative syntax for an if-else - the point is that if a() returns true, the entire expression resolves to the result of b(), else the entire expression resolves to the result of c().
As such, it doesn't make sense if b and c return void. They must return something, and the most specific type that they share will be the resulting type of the whole expression.

Related

Are the || ('or') symbol and Stream.of(..).anyMatch(e-> e==true) functionally equivalent? [duplicate]

This question already has answers here:
Why is Streams.allMatch(in Java8) trying to evaluate all the expressions even if the value can be determined midway?
(2 answers)
Closed 2 years ago.
Are || and Stream.of(..).anyMatch(e-> e==true) functionally equivalent when applied to the same series of conditions in the same order?
Task: Run a quick test on a series of conditions to determine whether any are true.
Possible solutions:
- Separate each condition with an ‘or’ symbol (||)
- Include each condition in a Stream.of(..) statement that is appended with .anyMatch(e-> e==true)
The documentation for anyMatch(..) states, “Returns whether any elements of this stream match the provided predicate. May not evaluate the predicate on all elements if not necessary for determining the result [emphasis added].”
Based on this statement, my understanding is that the two solutions indicated above are functionally the same, so that if the second element in a serious of four is the first element that is true, then elements three and four won’t be evaluated.
In practice, however, this seems not to be true. Consider the following where item is null, empty is true and UtilMethods.isEmpty(..) is a custom library method that tests if a given parameter is null or an empty String (""):
#Override
protected void updateItem(Pair<K, V> item, boolean empty) {
super.updateItem(item, empty);
boolean test1 = empty
|| Objects.isNull(item)
|| UtilMethods.isEmpty(item.toString())
|| Objects.isNull(item.getValue());
boolean test2 = Stream.of(
empty,
isNull(item),
UtilMethods.isEmpty(item.toString()),
isNull(item.getValue()))
.anyMatch(e -> e == true);
}
The || code runs as expected. However, the Stream.of(..).anyMatch(..) throws a NullPointerException when the third element is reached because item is null.
This doesn’t make sense in view of the documentation for anyMatch(..) that is referenced above, which suggests that the third element shouldn’t even be reached. Or am I missing something here?
Thanks
UtilMethods.isEmpty(item.toString()) is evaluated before Stream.of() is executed, so it will throw a NullPointerException regardless of whether or not you call anyMatch afterwards.
Stream.of(), just as any method call, evaluates all of its arguments before being executed, so it must evaluate UtilMethods.isEmpty(item.toString()).
You can see the same behavior in a much simpler snippet:
String s = null;
Stream<Integer> stream = Stream.of (5,s.length());
Hence, the documentation of anyMatch is irrelevant to the behavior you observed.
Your observation is correct. The two code snippets are indeed not the same. The important behaviour that || does, that Stream does not, is that || is short circuiting. When the first operand is true, || stops evaluating immediately. This is not true for the stream operation you have written. All 4 expressions:
empty,
isNull(item),
UtilMethods.isEmpty(item.toString()),
isNull(item.getValue())
Are evaluated before the stream even runs. Yes, anyMatch is lazy, but of is not. See what I mean? anyMatch will not evaluate e == true for every element if a previous element evaluated to true already. This does not apply to of.
To replicate the || behaviour, you'd have to wrap those 4 expressions into Supplier<Boolean>s, and evaluate them in anyMatch:
boolean test2 = Stream.<Supplier<Boolean>>of(
() -> empty,
() -> isNull(item),
() -> UtilMethods.isEmpty(item.toString()),
() -> isNull(item.getValue()))
.anyMatch(Supplier::get);
As you may long know, || uses shortcut evaluation, that is, if the first item it true, the second is never evaluated. This fact saves you from a NullPointerException in hte first case.
A stream pipeline has a similar behaviour: the final anyMatch only pulls enough elements from the stream to determine whether there is a match. So it may surprise that you get the exception. The explanation of Eran is correct, though: All the arguments of Stream.of() are evaluated before of is called to create the stream. This causes the exception. In other words, the stream never gets created. So the evaluation order in the stream never gets relevant in this case.
That this must be so is probably clearer to see if for a moment we forget that this is a stream operation and just look at it as Java method calls. The structure of the calls in your stream code is similar to the following, only I have simplified it a bit:
SomeClass.foo(ref.bar()).baz();
The sunshine order of evaluation of this expression is dictated by Java:
ref.bar() is evaluated to get the argument to pass to foo();
foo() is called;
baz() is called on the object returned from foo().
However if ref is null, the first step throws a NullPointerException and steps 2 and 3 are never performed. So there is nothing foo() nor baz() can do to change the order of evaluation nor to prevent the exception from happening. Similarly in your code there is nothing the stream pipeline can do to prevent all arguments to Stream.of() to be evaluated before of() is called to create the stream.
The rules about the order of evaluation were laid down in Java long before streams were introduced in the library and are similar to other programming languages. They wisely did not change them radically when introducing streams in Java 8. Sweeper in his answer shows a nice way to obtain the evaluation order you had expected.
Shortcut evaluation is explained in many places. One is here: What is the difference between the | and || or operators?

Is there any reason for Eclipse showing assignment variables in while loops as valid?

I've been punked numerous times while working on Java in eclipse when I write a while loop like so:
while (recsFinished = true)
When in reality I wanted
while (recsFinished == true)
It's a pretty simple mistake, but it happens to me a lot and it totally throws off the program. And the reason it does is because Eclipse doesn't even throw up a warning when I write the assignment as opposed to the equality equation. This leads me to believe there has to be some reason for a while loop with an assignment equation to exist, but why? I can't think of a single use!
Such assignments are popular in C and C++ (particularly within if statments) and have found themselves part of Java too.
Some folk put the literal on the left hand side: while (true == recsFinished) instead and I'm tempted to suggest that you adopt this programming style only that I personally find it obfuscating. This will issue a compiler error if = is used by accident.
Note well though that comparison to true is redundant. Drop it entirely and use while (recsFinished) instead.
It compiles, since it's valid Java syntax.
It's equivalent to :
recsFinished = true;
while (recsFinished) {
....
recsFinished = true;
}
Which is equivalent to
recsFinished = true;
while (true) {
....
recsFinished = true;
}
which would give you an infinite loop.
It is entirely possible to set a value in the expression of you while loop. If you do this your expression will be evaluated which is alway true because you reset it to true everytime you do a loop.
In most programming languages, the operator = return the assigned value after calling it.
whcih means if you want to assign a variable in every iteration and the value of this variable is the condition then you will use = in the loop condition instead of ==
Example
boolean a, b;
b = true;
while(a = b){
// Some crazy things using a & b
// loop ends when b == false at the end of an iteration
}
To answer your question; It's valid because the specification says so.
You can call a method with an expression,
15.12. Method Invocation Expressions
A method invocation expression is used to invoke a class or instance method.
MethodInvocation:
MethodName ( ArgumentList opt )
ArgumentList:
Expression
ArgumentList , Expression
and an assignment is an expression,
15.26. Assignment Operators
There are 12 assignment operators; all are syntactically right-associative (they group right-to-left). Thus, a=b=c means a=(b=c), which assigns the value of c to b and then assigns the value of b to a.
AssignmentExpression:
ConditionalExpression
Assignment

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...

Ternary Operators Java [duplicate]

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.

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