5

I have a dream....

In this dream I can replace such constructs as:

if(aLongVariableName.equals(classInstance.aPropertyOfThatInstance) ||  
   aLongVariableName.equals(classInstance.aDifferentProperty)){  
    ...  
}

with

if(aLongVariableName.equals(classInstance.aDifferentProperty || aPropertyOfThatInstance)){ 
   ...  
}

I think the later is more succinct, and easier to read. I'm sure something should be possible as methods can be declared with this kind of signature public void readUnlimitedVariables(Variable ... vars) which takes comma separated variables (as opposed to || or even &&).

This could be opened up to anything that returns a boolean, for instance:

if(myLovelyInstance instanceof AwesomeClass && EpicClass){
    ...
}

where myLovelyInstance implements AwesomeClass && EpicClass

Is this possible in Java? I've not found anything on this so far, by googling or on SO. If it's not in vanilla Java, are there any third party packages like Lombok or lambdaJ that would allow this? If not that either, if this a feature of any language? It seems very intuitive to me but I've not seen it anywhere.

Community
  • 1
  • 1
AncientSwordRage
  • 7,086
  • 19
  • 90
  • 173
  • 4
    why not wrap it into a class and override the equals method? – Bogdan Emil Mariesan Jun 29 '13 at 09:24
  • @BogdanEmilMariesan Because quite often I've wanted to do this with strings, and they seem to work just fine without my fiddling. If I knew how though I might try to do so. The best I can think of is a signature like so `readUnlimitedVariables(Variable ... vars,String AndOrChoice)` but even then I'm not 100% on how to implement. – AncientSwordRage Jun 29 '13 at 09:30
  • possible duplicate of [String.equals() with multiple conditions (and one action on result)](http://stackoverflow.com/questions/10208052/string-equals-with-multiple-conditions-and-one-action-on-result) – seanhodges Jun 29 '13 at 09:47
  • @seanhodges yeah it's similar, but I'm after more than just strings. – AncientSwordRage Jun 29 '13 at 14:54
  • @BogdanEmilMariesan I take that back. This would be great to work with lots of different things. See my edit. – AncientSwordRage Jun 29 '13 at 14:54
  • In that case, voted up :) – seanhodges Jun 30 '13 at 20:50

6 Answers6

8

Is this possible in Java?

No.

The || operator takes two boolean operands. There's no way to change this. Java does not allow you to overload operators, or to "extend the language syntax" in other ways.

The closest you could get would be to define a overload for equals like this:

public boolean equals(Object ... others) {
    for (Object other: others) {
        if (this.equals(other)) {
            return true;
        }
    }
    return false;
}

and use it like this:

if (aLongVariableName.equals(classInstance.aDifferentProperty,
                             classInstance.anotherProperty)) {
    ...  
}

... which is not really close at all. (And a pretty bad idea as well, IMO)

In fact, I can't think of any language that supports a syntax analogous to what you are proposing. It strikes me that there is too much potential for ambiguity for this to be a sound construct.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • I think this is a very bad idea because the Object[] is also an object and the decision on whether the client calls equals(Object) or equals(Object[]) depends only on the static type of the object in your code. THis is very error prone. However, what you could do is to define the method like this: public boolean equals(Object o1, Object o2, Object... moreObjects). In tis case, the one-element equals method has a sufficiently different signature. In general, when using varargs parameters it is a good idea to include one or two extra parameters for the first args. – avidD Jun 29 '13 at 15:17
  • 1
    Also, I'd rather call it oneOf(..) – avidD Jun 29 '13 at 15:24
  • 1
    Hey look, I agree. I merely included that method to illustrate that you really can't get close to what the OP is asking for. Another problem is how would you cope with `&&`, and mixed `||` and `&&` and so on. – Stephen C Jun 29 '13 at 15:54
5

For readability, you can use just simple variables, if the number of checking is small enough.

for example (the same for any type of objects)

boolean isPDFFile  = extension.equalsIgnoreCase("PDF");
boolean isHTMLFile = extension.equalsIgnoreCase("html");

if (isPDFFile || isHTMLFile ) {
   // do your processing
}

if you work with String, Regulare Expression is another way:

if (extension.matches("PDF|HTML")) {
   // do your processing
}

Sometimes simplicity is better than cleverness!

Wajdy Essam
  • 4,280
  • 3
  • 28
  • 33
3

Could you consider something like a bad practice? (I'm rather new to Java, so I might invent the wheel or just make bullsh*t :))

public class Main {
    public static <Type> boolean equalsVariadicOr(Type toComp, Type ... args) {
                for (Type arg : args) {
                        if (toComp.equals(arg)) {
                                return true;
                        }
                }
                return false;
        }

        public static <Type> boolean equalsVariadicAnd(Type toComp, Type ... args) {
                for (Type arg : args) {
                        if (!toComp.equals(arg)) {
                                return false;
                        }
                }
                return true;
        }

        public static void main(String args[]) {
                String testcaseAllA[]  = new String[] {"a", "a", "a", "a", "a", "a", "a", "a", "a", "a"};
                String testcaseWithB[] = new String[] {"b", "a", "a", "a", "a", "a", "a", "a", "a", "a"};
                System.out.println(equalsVariadicAnd("a", testcaseAllA));
                System.out.println(equalsVariadicAnd("b", testcaseWithB));
                System.out.println(equalsVariadicOr("b", testcaseWithB));
                System.out.println(equalsVariadicOr("a", testcaseAllA));
        }
}

If the answer is not, maybe OP will find this useful?

tkroman
  • 4,811
  • 1
  • 26
  • 46
  • Yeah, that isn't valid Java. You cannot make methods with generic parameters. You would have to make a generic class and instantiate at least one object of it to perform the `equalsVariadicAnd` or `equalsVariadicOr` methods. – E_net4 Jun 29 '13 at 09:53
  • 1
    It's actually valid code, it compiles and runs. I'm just asking if its efficient, java-ish and so on. Proof: http://ideone.com/I7unA6 – tkroman Jun 29 '13 at 09:53
  • I stand corrected. For some reason I thought generic methods did not exist in Java. – E_net4 Jun 29 '13 at 09:55
  • @E_net4, I made it generic because of I'm not sure if I'd just make arguments `Object`, one can obtain a possibility to call method comparing SomeClass with the list of AnotherClass, and that seems potentially dangerous for me, and generics provide a neat way to control types. – tkroman Jun 29 '13 at 09:58
  • On that, most comparisons return false when facing objects of a different class, though this is not a requirement. But no,comparing objects of different types isn't dangerous, and I hardly think it could throw exceptions. Nevertheless, generics is a good choice here. I should also point out that you are comparing references instead of objects. It's more than adequate to use `equals` instead of the `==` operator. – E_net4 Jun 29 '13 at 10:01
  • @E_net4, oh crap, that's a huge fail. Correcting it now, thanks a lot. – tkroman Jun 29 '13 at 10:05
2

You can get something very similar with varargs and Lombok's extension methods:

  1. Define the following static methods in a utility class:

    package test;
    
    public final class Util {
        private Util() {}
    
        public static boolean eqOr(Object tthis, Object ... those) {
            for (Object that : those) {
                if (tthis.equals(that)) return true;
            }
            return false;
        }
    
        public static boolean eqAnd(Object tthis, Object ... those) {
            for (Object that : those) {
                if (!tthis.equals(that)) return false;
            }
            return true;
        }
    }
    
  2. Use Lombok to make eqAnd and eqOr an extension methods:

    package test;
    
    @lombok.experimental.ExtensionMethod({test.Util.class})
    public class Work {
      public static void main(String[] args) {
        System.out.println("a".eqOr("b", "c", "a"));
        System.out.println("a".eqOr("b", "c"));
        System.out.println("a".eqAnd("a", "a", "a"));
        System.out.println("a".eqAnd("a", "a", "c"));
      }
    }
    

    Obviously, if you don't like lombok, you can use them just as regular static methods.

Jirka
  • 4,184
  • 30
  • 40
1

It's not possible in Java. The arguments of || must be booleans, and it's too late for .equals to decide, because it doesn't get both values, just a boolean.

To make it possible, the Java language specification has to be changed. I can't see a trend which would go this way, so you should tell the maintainers of Java that you'd like to have this. Even if they accept it, it might take years to make it to the language specification, and then years to get deployed to most Java installations.

pts
  • 80,836
  • 20
  • 110
  • 183
1

Don't forget about ecapsulation.

You can often clean up code by using instance methods:

In stead of a long, confusing if statement, you do this:

if (classInstance.matches(reallyLongVariableName)) {
    doStuff();
}

You bury the ugliness in a method:

class LongNamedObject {

    String propertyWithNameThatIsLong;
    String anotherLongNamedProperty;

    public boolean matches(String s) {
        return ( s.equals(propertyWithNameThatIsLong) ||
                 s.equals(anotherLongNamedProperty) );
    }
}

Writing boolean methods with expressive names is a great way to make code easier to read.

So often you see a mess like this:

if (userInputFile != null && userInputFile.getAbolutePath() != null 
      && user != null && user.getAccessRules() != null 
      && userHasAccess(user, userInputFile) {
    doStuff();
}

And it could look like this:

if (isValid(userInputFile, user)) {
    doStuff();
}

You bury the ugliness in a method:

private boolean isValid(File f, User u) {
    if (u == null || f == null) {
        return false;
    }
    if (f.getAbsolutePath() == null) {
        return false;
    }
    if (u.getAccessRules() == null) {
        return false;
    }
    return userHasAccess(u, f);
}
jahroy
  • 22,322
  • 9
  • 59
  • 108