1


I have the following situation. I have some class A, which has list of objects of type B. Type B has two properties X, Y of type string and two getters getX() getY(). I would like to have a method in class A such that returns an object from collection of B objects selected by given value of string. For example:

B findElementByX(String x) { for (B i : list) { if (i.getX().equals(x) return i; } return null; } 

For the other property Y i would have almost the same code, btu instead of getX(), there will be getY(). For me its unnecessary redundance of code. My question is: how to write this method in order to have one method to find by either X or Y property value? Is this a generic way to solve this in Java?

2
  • Shouldn't that be for (B i : list) ? Commented Nov 18, 2012 at 13:59
  • According to your question both X and Y are of same type String. How could apply generics on same type. But can be done by reflection. Also the datatype of i would be B I guess. Commented Nov 18, 2012 at 14:00

3 Answers 3

4

You could have a function

B findElementByProperty(String prop, PropertyExtractor<B,String> propEx) 

where PropertyExtractor<B,P> is a generic function pointer to a function of B returning type P.

Just that Java does not have function pointers. So PropertyExtractor<B,P> could instead be an interface with a single method, say P getProperty(B obj), of which you would of course need two implementations (wrapping a call to getX and getY, respectively).

You can easily see that this will not save you many lines of code, however. To the contrary.

Sign up to request clarification or add additional context in comments.

Comments

2

You can reduce code size for things like this by using something like Guava, which supplies something resembling functional language style list comprehension.

You can also roll some of this yourself, by defining an interface

public interface Predicate<T> { boolean apply(T obj); } 

and then creating a finder method using it:

B findElementByPredicate(Predicate<B> predicate) { for (B b : list) { if (predicate.apply(b)) return b; } return null; } 

You can also (as noted in a comment) use reflection to get the value of a field. Implementing the interface defined in arne.b's answer, you can define

public class ReflectivePropertyExtractor<T, P> implements PropertyExtractor<T, P> { String fieldName; public ReflectivePropertyExtractor(String fieldName) { this.fieldName = fieldName; } @Override public P getProperty(T obj) { try { Method m = B.class.getMethod(makeAccessorName()); return (P) m.invoke(obj); } catch (InvocationTargetException e) { return null; } catch (NoSuchMethodException e) { return null; } catch (IllegalAccessException e) { return null; } } private String makeAccessorName() { return "get" + capitalize(fieldName); } private String capitalize(String s) { if ((s == null) || (s.length() == 0)) return s; return s.substring(0, 1).toUpperCase() + s.substring(1); } } 

to make a property extractor that works for a specified field name, and either use that as he described in his answer or make a predicate based on it:

public class PropertyMatchPredicate<T, P> implements Predicate<T> { private final P matchValue; private final PropertyExtractor<T, P> extractor; public PropertyMatchPredicate(P matchValue, PropertyExtractor<T, P> extractor) { this.matchValue = matchValue; this.extractor = extractor; } @Override public boolean apply(T obj) { return matchValue.equals(extractor.getProperty(obj)); } } 

and then use that predicate in the findByPredicate above:

B findElementByProperty(String matchField, final String matchValue) { final ReflectivePropertyExtractor<B, String> extractor = new ReflectivePropertyExtractor<B, String>(matchField); return findElementByPredicate(new PropertyMatchPredicate<B, String>(matchValue, extractor)); } 

If you are only dealing with two properties, all of these tactics will likely increase code size rather than decreasing it. The advantages only happen at greater scale, and you may pay a price in making your code less readable to people unfamiliar with functional style and/or reflection.

Comments

1

Pass X or Y as another parameter to find the getX() or getY() else return null.

B findElementByXY(String s,String identifier) { for (X i : list) { if ("X".equals(identifier)&&i.getX().equals(s)) return i; else if ("Y".equals(identifier)&&i.getY().equals(s)) return i; } return null; } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.