I have a Collection<A>
class A {
String name;
Long id;
}
Now I have UI screen where I can provide name & id value to match this collection and display the result.
Now I have 3 criteria:
I can do it by three if
check-based on null check of UI fields but I don't want to make if-else
block because if I have multiple UI fileds it would be hectic to do nested if-else
check.
Please suggest a better way in java 7.
You could provide some predicates that are used to filter the collection. Since java.util.function.Predicate
has only been added with Java 8 you'd need to either roll your own or use a library such as Google Guava .
With that you could pass the predicates to be used in a filter:
Collection<Predicate<A>> predicates = ...;//you get them from your UI
Collection<A> filtered = Collections2.filter( originalCollection, Preciates.and( predicates ) );
The predicates could then look like this:
class ANamePredicate implements Predicate<A> {
private String name;
public ANamePredicate( String n) {
name = n;
}
boolean apply(@Nullable A input) {
//if one or both could be null, add handling for that
return input.name.equals(n);
}
//implement equals(...) as well
}
Of course you could use anonymous classes as well but you'd then probably want to provide for an abstract base class that remove the requirement to always implement equals()
:
abstract class AbstractPredicate<T> implements Predicate<T> {
public boolean equals( Object o) {
//simplified, you might have to provide a better implementation, e.g. you want to provide a set of predicates
return false;
}
}
Then you create a collection of predicates when needed:
Collection<Predicate<A>> predicates = new LinkedList<>();
predicates.add( new AbstractPredicate<A>() {
boolean apply(A input) {
return "Skabdus".equals(input.name);
}
} );
predicates.add( new AbstractPredicate<A>() {
boolean apply(A input) {
return input.id == 1;
}
} );
You could use the decorator pattern with expressions. The principle is to have an interface that each "criteria" will implement (with one method : eval) and to have a distinction bewteen terminal operators and not terminal operators .
You would have a NameIsSet class, an IdIsSet class as terminal opeators (or other classes if you have other implementations in the future), and logical expressions as non-terminal operators : And , Or , Not , ...
Then, you should use the pattern this way :
Predicate predicate = new And(new IdIsSet("id"), new Not(new NameIsSet("name")));
if(predicate.eval()){
// Do something
}
If you want to set a particular behaviour for each case, you could create a List of these predicates and set a method to call if the predicate is true :
for(Predicate predicate: predicateList){
if(predicate.eval()) {
predicate.execute();
//break if only one case is accepted
}
}
Here is a sample of And class and NameIsSet class:
public class And implements Predicate{
private Predicate pred1;
private Predicate pred2;
public And(Predicate p1, Predicate p2){
this.pred1 = p1;
this.pred2 = p2;
}
@Override
public boolean eval(){
return this.pred1.eval() && this.pred2.eval();
}
@Override
public void execute(){
// Not sure of you want to do here
}
}
public class NameIsSet implements Predicate{
private String name;
public NameIsSet (String name){
this.name = name;
}
@Override
public boolean eval(){
return this.name == null || this.name.length = 0;
}
@Override
public void execute(){
// Not sure of you want to do here
}
}
In this implementation, you must create all your predicates beforehand, add them to a list and set the execute() method for each.
Hope this will be useful to you.
Your if
statements don't need to be nested. You can, for example, do this:
static boolean matches(A candidate, A pattern) {
if (pattern.name != null && !candidate.name.equals(pattern.name))
return false;
if (pattern.id != null && !candidate.id.equals(pattern.id))
return false;
return true;
}
This scales at a 1:1 rate with any number of fields. (You could use candidate.id != pattern.id
there, but I used equals
for consistency.)
If you have dozens of fields and you don't want to name them individually, you can use reflection and process all the fields with a single for
loop:
static boolean matches(A candidate, A pattern) throws IllegalAccessException {
for (Field fld : A.class.getDeclaredFields()) {
Object c = fld.get(candidate);
Object p = fld.get(pattern);
if (p != null && !c.equals(p))
return false;
}
return true;
}
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.