Reputation: 13
I am currently implementing a way to match a Predicate to a text string
To do that matching I'm filling a Map of < Predicate, String> and then I can retrieve the corresponding String via the predicate.
The problem is that when using a parameterized predicate like in the code below the same predicate match for different parameters (valueToTest not used in the hashing function)
public static Predicate<MyObject> predicateCondition(String valueToTest) {
return myObject -> myObject.value.equals(valueToTest);
}
So currently I need to make one predicate per parameter I would want to test ie :
public static Predicate<MyObject> predicateConditionValue1() {
return myObject -> myObject.value.equals("value1");
}
public static Predicate<MyObject> predicateConditionValue2() {
return myObject -> myObject.value.equals("value2");
}
Would there be another way to avoid duplicating the predicate?
Upvotes: 1
Views: 208
Reputation: 669
tl;dr:
First at all you should to know that Predicate is not class but it is interface. And lambda's are almost anonymous classes (with few differences, which are not important in scope of your question). So all your three functions which you've show in your question, returns objects which are instances of three different classes (of course, all of them implement same interface, that's why you can use all of them as keys in Map). But map (which is actually interface too, so you need to understand how works exact map implementation, which you're using in your code) usually use equals(), hashCode() and sometimes maybe compareTo() of your key-class. And because you're using anonimous classes (strictly: 'almost anonymous classes'), it uses equals() and hashCode() from class Object. Where hashCode() not depends on object methods and data, but created by JRE, and equals() compares that hash-codes.
Briefly:
Don't use anonimous (declared as lambda) predicates as keys in your map. Create your own class which implements Predicate interface and have your own implementation of hashCode(), equals() and test(). If you still want use lambda's, use these anonimous predicates as field of you own key-class.
Generally:
To avoid such problems just consider Lambda's in java as a syntax sugar (lambda's are not just syntax sugar, but almost syntax sugar). When you're writing code:
Predicate<String> aPredicate= s->"asd".equals(s);
consider it as special form of code below:
Predicate<String> aPredicate= new Predicate<String>() {
@Override
public boolean test(String s) {
return "asd".equals(s);
}
};
Upvotes: 1
Reputation: 44378
To avoid duplicating predicates, you should rather use BiPredicate<T,U>
which accepts one more parameter and produces a Boolean
as well.
BiPredicate<MyObject, String> biPredicate = (obj, string) -> myObject.value.equals(string)
In a method:
public static BiPredicate<MyObject, String> predicateConditionValue() {
return (myObject, string) -> myObject.value.equals(string);
}
Upvotes: 0
Reputation: 18245
As alternative you can use BiFunction
instead:
BiFunction<MyObject, String, Boolean> isEquslTo = (myObject, expected) -> Objects.equals(myObject.value, expected);
But I like approaches with two Predicate
more.
Upvotes: 0