Simple Implementation of .NET Array/List's Generic FindAll Method in Java

Kevin CrossChief Technology Officer
CERTIFIED EXPERT
Father, husband and general problem solver who loves coding SQL, C#, Salesforce Apex or whatever.
Published:
Updated:
After being asked a question last year, I went into one of my moods where I did some research and code just for the fun and learning of it all.  Subsequently, from this journey, I put together this article on "Range Searching Using Visual Basic.NET".  Being the Java nut that I am, I would not have felt complete, if I didn't also play with this topic in Java; therefore, you can also read on "Range Searching Using Java" which has the origins of some of the code used in this article.

What does the FindAll method have to do with anything?
[The FindAll generic method] retrieves all the elements that match the conditions defined by the specified predicate.

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.

System.Array.FindAll(arrayOfObjects, _
                         New Predicate(Of String)(AddressOf MatchRange) _
                      )

Open in new window


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.

'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

Open in new window


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.


/**
                       * 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);
                      }

Open in new window

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.
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);
                          }
                      }

Open in new window

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!


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("");
                          }
                      }

Open in new window

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.
Predicates.findAll(numbers, new Predicate<Number>() {
                          @Override 
                          public boolean isMatch(Number n) { 
                              return isLessThan50(n); 
                          }
                      });

Open in new window


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)
2
7,192 Views
Kevin CrossChief Technology Officer
CERTIFIED EXPERT
Father, husband and general problem solver who loves coding SQL, C#, Salesforce Apex or whatever.

Comments (1)

Kevin CrossChief Technology Officer
CERTIFIED EXPERT
Most Valuable Expert 2011

Author

Commented:
Here is an official white paper from Sun, discussing usage of Reflection API to implement delegation in Java using the J++ methodology :
http://java.sun.com/docs/white/sidebar.html

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/blog/alexwinston/archive/2005/04/strongly_types_1.html

Regards,
Kevin

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.