What does the FindAll method have to do with anything?
Very concise definition for a nice generic method in .NET I found to be similarly short and sweet. In my research, the goal was to create a more efficient means of searching for values in an array/list that met specific criteria without having to loop through each value. What I found was the FindAll method proved to be faster both in performance and actual code implementation.
1: 2: 3: 4: | System.Array.FindAll(arrayOfObjects, _ New Predicate(Of String)(AddressOf MatchRange) _ ) |
Just one line of code to use as FindAll utilizes a delegate function known as a Predicate that takes one argument and returns a true or false if the argument meets criteria specified within the predicate's implementation.
1: 2: 3: 4: | 'Delegate implementation for Predicate needed in System.Array.FindAll
Function MatchRange(ByVal n As String) As Boolean
Return Ranges.MatchRange(n, RANGE_START, RANGE_END)
End Function
|
For a better look at delegates from a Java perspective, you can read "A Java Programmer Looks at C# Delegates" by Steven M. Lewis and Wilhelm Fitzpatrick.
For my simple implementation, I chose to go with a Predicate interface and anonymous inner classes to simulate the delegate functionality.
- 1
- Create Predicate Interface.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
/** * Predicate interface used to emulate .NET * <code>System.Predicate(Of T)</code>. */ package com.blogspot.crossedlogic.rangesearching; public interface Predicate<T> { /** * @param obj - object to test against predicate criteria. * @return boolean flag indicating a match (true) or no match (false). */ public boolean isMatch(T obj); }
- 2
- Create FindAll Function.
In .NET, you can utilize shared (static) functions from the List/Array class or from an instance of an implementation of List; therefore, a findAll method could be added to a custom List implementation in Java, but the code I went with uses a utility class that I could store other functions relating to predicates.1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51:
package com.blogspot.crossedlogic.rangesearching; import java.util.ArrayList; import java.util.List; public class Predicates { /** * Replicate .NET findAll and <code>Predicate</code>. * * @param <T> * @param array - an array of objects of type <T>. * @param match - * <p> * instance of an implementation of the Predicate * interface. * </p> * @return List<T> representing all matches found. * @see com.blogspot.crossedlogic.rangesearching.Predicate */ public static <T> List<T> findAll(T[] array, Predicate<T> match) { List<T> lst = new ArrayList<T>(); for (T obj : array) { if (match.isMatch(obj)) { lst.add(obj); } } return lst; } /** * Replicate .NET findAll and <code>Predicate</code>. * * @param <T> * @param list - collection of objects of type <T>. * @param match - instance of an implementation of the * Predicate interface. * @return List<T> representing all matches found. * @see com.blogspot.crossedlogic.rangesearching.Predicate */ @SuppressWarnings("unchecked") public static <T> List<T> findAll(List<T> list, Predicate<T> match) { return findAll((T[]) list.toArray(), match); } }
Originally, I implemented only the findAll with array argument in signature as it allowed for use with both arrays and lists through one function, but given the ability to overload methods I added the second as it makes calls easier when searching lists as you can simply pass the List object without having to convert it to an array first.
- 3
- Enjoy!
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69:
package com.expertsexchange.articles; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; import com.blogspot.crossedlogic.rangesearching.Predicate; import com.blogspot.crossedlogic.rangesearching.Predicates; public class PredicateMatchExample { /** * @param args */ public static void main(String[] args) { List<Number> numbers = new ArrayList<Number>(); List<Number> matches; for (int i = new Random(System.currentTimeMillis()) .nextInt(10); i < 100; i += 7) { numbers.add(i); } displayNumbers(numbers, "All Numbers"); // find all the perfect squares. matches = Predicates.findAll(numbers .toArray(new Number[] {}), new Predicate<Number>() { @Override public boolean isMatch(Number n) { double sqrt = Math.sqrt(n.doubleValue()); return Math.ceil(sqrt) == sqrt; } }); displayNumbers(matches, "Perfect Squares"); // find all numbers less than 50. matches = Predicates.findAll(numbers, new Predicate<Number>() { @Override public boolean isMatch(Number n) { // mimic .NET delegate method; // utilize existing method for // implementation. return isLessThan50(n); } }); displayNumbers(matches, "Less Than 50"); } static boolean isLessThan50(Number n) { return n.intValue() < 50; } static void displayNumbers(List<Number> numbers, String title) { System.out.printf("%s: %s.", title, (numbers.size() > 0) ? Arrays.toString( numbers.toArray()).replaceAll( "^\\[|\\]$", "") : "none"); System.out.println(""); } }
As mentioned earlier, the anonymous inner class within Java allows you to utilize methods from your main class similar to the delegate function in .NET. Looks a little more than one line, but hopefully you agree that this is not a lot of Java code for what you are getting.1: 2: 3: 4: 5: 6: 7:
Predicates.findAll(numbers, new Predicate<Number>() { @Override public boolean isMatch(Number n) { return isLessThan50(n); } });
I found the FindAll method very useful and I am hoping you will as well. In addition, having a Predicate concept in Java may come in handy for other projects as well.
Thanks for taking the time to read the above. If you have any questions on how the code works that is not explained well enough in the code comments, please post below and I will be happy to clarify.
Happy coding!
Best regards,
Kevin (aka MWVisa1)
http://java.sun.com/docs/w
And this follow-up article goes into strongly typed delegates (it references above, so good to read in order linked here) :
http://weblogs.java.net/bl
Regards,
Kevin