Java: Ternary with no return. (For method calling)

30,806

Solution 1

No, you can't. But what's the point of this over an if-else statement? Are you really trying to save 7 characters?

if (name.isChecked()) {
    name.setChecked(true);
} else {
    name.setChecked(false);
}

or if you prefer bad style:

if (name.isChecked()) name.setChecked(true); else name.setChecked(false);

Never mind the fact that you can just do (in this case):

name.setChecked(name.isChecked());

The point of the ternary or "conditional" operator is to introduce conditionals into an expression. In other words, this:

int max = a > b ? a : b;

is meant to be shorthand for this:

int max;
if ( a > b ) {
    max = a;
} else {
    max = b;
}

If there is no value being produced, the conditional operator is not a shortcut.

Solution 2

I was wondering if it was possible to do a ternary operation but without returning anything.

No it is not possible:

  1. The 2nd and 3rd operands are required to be non-void expressions; i.e. they must produce some actual value.

    "It is a compile-time error for either the second or the third operand expression to be an invocation of a void method." - JLS 15.25.

  2. A ternary expression is an expression, and cannot be used as a statement.

    "Certain kinds of expressions may be used as statements by following them with semicolons." ... and the ternary expression is not one of those kinds - JLS 14.8.

If you really, really want to use a ternary expression but not use the value of the expression, then the simplest thing is to assign the value to a dummy variable, and add an annotation to suppress the warning about the variable not being used.

But a better idea is to use a plain if statement.

If it's not possible in Java is it possible in other languages, if so which ones apply?

I'm a bit rusty, but I believe that C, C++ and Perl all allow arbitrary expressions to be used in places where their values are not used.

Solution 3

Sometimes, you can use ternary operation on method arguments to solve your request.

name.setChecked(name.isChecked() ? true : false);

By the way, the best solution for your problem is

name.setChecked(name.isChecked());

Solution 4

I assume the use case in the question is just a poor example because it's equivalent to the following statement:

name.setChecked(name.isChecked());

... which doesn't make sense either. But the intent is clear and there are indeed many relevant use cases.

The only viable and general solution is adding a helper method like this:

static void ternaryVoid(boolean condition, Runnable ifTrue, Runnable ifFalse) {
    (condition ? ifTrue : ifFalse).run();
}

and using it like this:

ternaryVoid(name.isChecked(), () -> name.setChecked(true), () -> name.setChecked(false));

But it loses the elegance of ternary operator and worth the 'effort' only if used by multiple parts of the code and only if nanoseconds don't matter.

But what's the point of this over an if-else statement? Are you really trying to save 7 characters?

I'm surprised that such statements appear in a form of rhetorical questions. Yes, saving 4 lines and making the code more elegant is important, especially in the context of functional programming.

Moreover, it's at least arguable whether void methods return a complete Void. Essentially, they return a notification of a completed task. This is why logically, ternary expression makes sense equally regardless of whether it returns something or nothing:

condition ? doThis() : doThat();

Here is a real world example of a class which may process millions of incremental updates per second:

public class DataHandler {

    private final TreeMap<Integer, Long> tree = new TreeMap<>();

    public void onUpdate(int price, long amount) {
        if (amount == 0) {
            tree.remove(price);
        } else {
            tree.put(price, amount);
        }
    }
}

If allowed, the onUpdate() method would be a nice ternary expression like this:

public void onUpdate(int price, long amount) {
    (amount == 0) ? tree.remove(price) : tree.put(price, amount); // compilation error
}

Fortunately, in some cases like this, both target methods return values, and these values are of the same type, which is Long in this case. This allows either to make the onUpdate method to return the previous amount at price (which is even useful)

public Long onUpdate(int price, long amount) {
    return (amount == 0) ? tree.remove(price) : tree.put(price, amount);
}

... or alternatively (e.g. in case the method is determined by an interface), to use a dummy variable and suppress its uselessness warning:

public void onUpdate(int price, long amount) {
    @SuppressWarnings("unused")
    Long dummy = (amount == 0) ? tree.remove(price) : tree.put(price, amount);
}

Otherwise, these solutions are not applicable, and as answered by others, doesn't exist. For instance, one may try the following:

Consumer<Void> dummy = (x) -> {};
dummy.accept(/*...*/);

but interestingly, the second line compiles with neither anything nor nothing as an argument.

It seems the best general solution is the above helper method ternaryVoid().

Share:
30,806
TylerKinkade
Author by

TylerKinkade

Developer @ MEDL Mobile.. Android / iOS / Unity !k

Updated on July 09, 2022

Comments

  • TylerKinkade
    TylerKinkade almost 2 years

    I was wondering if it was possible to do a ternary operation but without returning anything.

    If it's not possible in Java is it possible in other languages, if so which ones apply?

    name.isChecked() ? name.setChecked(true):name.setChecked(false);
    
  • jalv1039
    jalv1039 over 7 years
    (your-condition) ? (true-statements) : (false-statements) is possible in java but it has to return a value (it cannot be void) and you have to assign it to a variable.
  • zuazo
    zuazo over 7 years
    This question is already answered. Please, read the FAQ to learn how to ask questions properly.
  • Jamby
    Jamby almost 3 years
    Using Stream.forEach lambda there are cases where in my opinion writing (item -> item.isA() ? doA() : doB()) would be far more elegant than expanding with curly brackets and if/else.
  • html_programmer
    html_programmer almost 2 years
    What is the argument for not being able to? Just makes sense for cleaner code in some cases.
  • Mark Peters
    Mark Peters almost 2 years
    @html_programmer: Of course other arguments could be made, but my personal opinion is that delineating control structures with side effects and conditional expressions leads to cleaner code. IMO burying a side effect in an expression hides the most important part of the code, both here and with the related someConditionTrue && doSideEffect() that you sometimes see. But as with much code style, it's highly subjective.