37

Is there a way to do a java ternary operation without doing an assignment or way to fake the assingment?

I like how succinct ternary code looks when doing a bunch of if/then/elses.

I'm hoping to be able to call one of two void functions based on a boolean algebra statement.

Something like:

(bool1 && bool2) ? voidFunc1() : voidFunc2();

My functions are of return type void, so if there is a way to fake this in an assignment to make it work, then I"m okay with that... I would like to see how to do it though :)

James Oravec
  • 19,579
  • 27
  • 94
  • 160
  • 1
    @VenomFangs you may change your functions to return a constant value always, and assign this return value to a dummy variable. But it's not worth the hassle - code will look stupid, I'm afraid. Better to do it as you already know you should do. – Igwe Kalu Apr 12 '13 at 17:15

4 Answers4

30

Nope you cannot do that. The spec says so.

The conditional operator has three operand expressions. ? appears between the first and second expressions, and : appears between the second and third expressions.

The first expression must be of type boolean or Boolean, or a compile-time error occurs.

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

[EDIT]

Since you asked about reflection, here's a solution. I'm not recommending this. I'm posting it only because you asked.

public class MyCall
{

    public void a(){System.out.println("a");}
    public void b(){System.out.println("b");}

    public static void main(String... args)
    {
        new MyCall().go();
    }

    public void go()
    {
        Class<? extends MyCall> class1 = this.getClass();
        Method aMethod = class1.getMethod("b", null);
        Method bMethod = class1.getMethod("a", null);
        Object fake = false ? aMethod.invoke(this, null) : bMethod.invoke(this, null);
        Object fake2 = true ? aMethod.invoke(this, null) : bMethod.invoke(this, null);
    }
}

At the end of the day you've got to ask yourself if being succint improves your code's readability (think for-each loop). None of these solutions improve the code's readability IMHO. If I were you I'd rather go with this.

if(condition)
    a();
else
    b();

I'm actually for including braces even when loops only contain a single line, but since you're going after crisp code, the snippet above should do.

Deepak Bala
  • 11,095
  • 2
  • 38
  • 49
  • Any thoughts on the reflection comment in: http://stackoverflow.com/questions/4830843/in-java-is-it-possible-to-cast-to-void-not-void – James Oravec Apr 12 '13 at 17:11
  • Is there a way to make the void reflect to null then assign null to an object? – James Oravec Apr 12 '13 at 17:12
  • 2
    Edited my answer with a reflective solution. For academic purposes of course :) – Deepak Bala Apr 12 '13 at 17:25
  • Answers the question I asked, so I'll accept the answer... My actual code will look more like that of inline if/then/else that TGMCians showed. :) – James Oravec Apr 12 '13 at 18:03
  • This has been long answered but I had an idea. (NB: I'm no pro). What if he had those void functions return an integer instead. Say - 1. Then he runs `int fake = bool ? method1 : method2;` they both return - 1 but the required code still runs. I use this and haven't run into any trouble yet. – kbluue Dec 20 '16 at 02:18
  • "It is a compile-time error for either the second or the third operand expression to be an invocation of a void method." No. Not just void method. It can't be an invocation of any method. https://stackoverflow.com/questions/56896918/not-a-statement-why-not – Seshadri R Jul 05 '19 at 06:04
12

No, you can't do this like this.

You can prefer this style if do not like make it more statements.

if(bool1 && bool2) voidFunc1(); else voidFunc2();

In ternary operator, Operands are required to be non-void expressions; i.e. they must produce some actual value.

Ajay S
  • 48,003
  • 27
  • 91
  • 111
  • I like this presentation... I'll accept this answer if no one else can show me a way to do it. E.g. By the reflection of void to null... etc. – James Oravec Apr 12 '13 at 17:13
3

Is there a way to do a java ternary operation without doing an assignment or way to fake the assignment?

OK, so when you write a statement like this:

    (bool1 && bool2) ? voidFunc1() : voidFunc2();

there are two distinct problems with the code:

  1. The 2nd and 3rd operands of a conditional expression1 cannot be calls to void methods. Reference: JLS 15.25.

  2. An expression is not a statement, unless it is either and assignment expression OR a method call OR a object creation. Reference: JLS 14.8.

In fact, the second of these problems is a syntax error and I would expect any mainstream Java compilers to report it instead of the first problem. The first problem would only reveal itself if you did something like this:

    SomeType dummy = (bool1 && bool2) ? voidFunc1() : voidFunc2();

or

    gobble((bool1 && bool2) ? voidFunc1() : voidFunc2());

where gobble is a method that does nothing ... except "consume" the value of its argument.

AFAIK, there is no context in which the original expression is acceptable.

However, there are ways to wrap the void functions so that they can be called in a conditional expression. Here is one:

 int dummy = (bool1 && bool2) ? 
     () -> {voidFunc1(); return 0;} : 
     () -> {voidFunc2(); return 0;};

1 - "Conditional expression" is the primary term used for this construct in the Java Language Specification. It is called the "ternary conditional operator" in Oracle Java Tutorial.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
2

If you really-really want to use ternany operation, then there is one hack. BUT this is very bad code, intended only for showing abilities of language. I would never recommend to put this code in production or even show to your friends.

int dummy = (bool1 && bool2) ? new Object(){
        public int hashCode() {
            yourFunction1();
            // ...
            yourFunctionN();
            return 0;
        };
    }.hashCode() : new Object(){
        public int hashCode() {
            yourAnotherFunction1();
            // ...
            yourAnotherFunctionN();
            return 0;
        };
    }.hashCode();
Alex Turbin
  • 2,554
  • 2
  • 22
  • 35