简体   繁体   中英

How can I use a ternary operator mixed with logical OR?

I have one superclass Foo and many subclasses Bar1 .. BarN that extends the superclass.

public Foo { .. }

public Bar extends Foo { .. }

public Bar2 extends Foo { .. }
.......
public BarN extends Foo { .. }

I was trying to determine type of child class during runtime then move on to next operation via if, else-if, else statements however I decided to try something new to see if I could reduce number of lines of code so that I came up with below code and there was no compile error. However it didn't cover all the instances of child class.

private void doSomething(Foo foo) {
    boolean trigger = false;
    if ( (trigger = foo instanceof Bar ? true : false)
                || (trigger = foo instanceof Bar2 ? false : true) ) {
        if (trigger == true) { // do Bar thing }
        else { // do Bar2 thing }
    }
 }

So I said to myself instead of using boolean type for trigger variable, let me use int type for the same variable. Such as 1 for Bar , 2 for Bar2 , 3 for Bar3 and etc. So I re-engineered my code then I got a compile error saying "The operator || is undefined for the argument type(s) int,int" in first if statement. I am not sure how to interpret the message.

private void doSomething(Foo foo) {
    int trigger = 0;
    if ( (trigger = foo instanceof Bar ? 1 : 0)
                || (trigger = foo instanceof Bar2 ? 2 : 0) ) {
        if (trigger == 1) { // do Bar thing }
        else if (trigger == 2) { // do Bar2 thing }
    }
 }

Just use the Visitor Pattern .

Rather than telling you how to make it work the way you are trying to do it (for what it's worth, @Sebastian's answer is a clean way of doing what you've been trying to do ), here is a way to do it faster and more legibly.

Use object orientation to your advantage here, rather than wasting all this complexity with likely slow instanceof checks. This will allow you to keep the behavior for each implementation of Foo to handle every class individually, with the behavior in a separate method so it doesn't get confusing. It's branchless, which means that you don't have to do any if calls which can be slow and cumbersome, as you noticed yourself. The code is easier to follow and faster.

Here's how it works (this is boilerplate, you don't do any logic here):

public interface Foo {
  void accept(FooVisitor visitor);
}

public class Bar implements Foo {
  void accept(FooVisitor visitor) {
    visitor.visit(this);
  }
}

public class Bar2 implements Foo {
  void accept(FooVisitor visitor) {
    visitor.visit(this);
  }
}

Then, in your class that you've been writing, do (this is where the behavior goes):

private void doSomething(Foo foo) {
  foo.accept(this);
}

private void visit(Bar bar) {
  // do Bar thing
}

private void visit(Bar2 bar2) {
  // Do Bar2 thing
}

You probably want something like:

int trigger = (foo instanceof Bar) ? 1 :
              (foo instanceof Bar2) ? 2 :
              (foo instanceof Bar3) ? 3 :
               0; // in case it's not an instance of any

Honestly, your code (even if it can be made to compile) doesn't seem readable. One way is to use a switch on the class name (requires Java 7+):

String className = foo.getClass().getName();
switch(className) {

   case mypackage.Bar:
        // do something

   case mypackage.Bar1:
        // do something
   ...
}

Alternatively you can rely on polymorphism where every subclass implements a method declared in Foo :

class Foo {

   void doSomething() {
   }
}

class Bar extends Foo {

   @Override
   void doSomething() {
      // something for Bar
   }
}

class Bar1 extends Foo {

   @Override
   void doSomething() {
      // something for Bar1
   }
}

If you don't want to change the classes to do this, you can use the Visitor pattern described by @durron597.

You cannot use the || operator with non-boolean types.

Also, you can simplify your if statements to something like the following.

if (foo instanceof Bar || foo instanceof Bar2) { }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM