Guava’s Collections2: Filtering and Transforming Java Collections
One of the conveniences of Groovy is the ability to easily perform filtering and transformation operations on collections via Groovy’s closure support. Guava brings filtering and transformation on collections to standard Java and that is the subject of this post.
Guava’s Collections2 class features two public methods, both of which are static. The methods filter(Collection, Predicate) and transform(Collection, Function) do what their names imply: perform filtering and transformation respectively on a given collection. The collection to be filtered or transformed is the first parameter to each static method. The filtering function’s second argument is an instance of Guava’s Predicate class. The second argument of the transformation function is an instance of Guava’s Function class. The remainder of this post demonstrates combining all of this together to filter and transform Java collections.
Filtering Collections with Guava
Filtering collections with Guava is fairly straightforward. The following code snippet demonstrates a simple example of this. A Set
of String
s is provided (not shown in the code snippet, but obvious in the output that follows the code) and that provided Set
is filtered for only entries beginning with a capital ‘J’. This is done via use of Java regular expression support and Guava’s Predicates.containsPattern(String), but there are other types of Predicates that can be specified.
Filtering Strings Beginning with ‘J’
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | /** * Demonstrate Guava's Collections2.filter method. Filter String beginning * with letter 'J'. */ public static void demonstrateFilter() { printHeader( 'Collections2.filter(Collection,Predicate): ' J ' Languages' ); final Set<String> strings = buildSetStrings(); out.println( '\nOriginal Strings (pre-filter):\n\t' + strings); final Collection<String> filteredStrings = Collections2.filter(strings, Predicates.containsPattern( '^J' )); out.println( '\nFiltered Strings:\n\t' + filteredStrings); out.println( '\nOriginal Strings (post-filter):\n\t' + strings); } |
The output from running the above method is shown next. This output shows the lengthy list of programming languages that make up the original Set
of String
s returned by buildSetStrings()
and shows the results of the filter call featuring only those programming languages that begin with ‘J.’
Transforming Collections with Guava
Transforming collections with Guava works similarly to filtering syntactically, but a Function
is used to specify how source collection entries are ‘transformed’ to the output collection rather than using a Predicate
to determine which entries to keep. The following code snippet demonstrates transforming entries in a given collection to the uppercase version of themselves.
Transforming Entries to Uppercase
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | /** * Demonstrate Guava's Collections2.transform method. Transform input * collection's entries to uppercase form. */ public static void demonstrateTransform() { printHeader( 'Collections2.transform(Collection,Function): Uppercase' ); final Set<String> strings = buildSetStrings(); out.println( '\nOriginal Strings (pre-transform):\n\t' + strings); final Collection<String> transformedStrings = Collections2.transform(strings, new UpperCaseFunction<String, String>()); out.println( '\nTransformed Strings:\n\t' + transformedStrings); out.println( '\nOriginal Strings (post-transform):\n\t' + strings); } |
The above transformation code snippet made use of a class called UpperCaseFunction
, but you won’t find that class in the Guava API documentation. That is a custom class defined as shown in the next code listing.
UpperCaseFunction.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | package dustin.examples; import com.google.common.base.Function; /** * Simple Guava Function that converts provided object's toString() representation * to upper case. * * @author Dustin */ public class UpperCaseFunction<F, T> implements Function<F, T> { @Override public Object apply(Object f) { return f.toString().toUpperCase(); } } |
The output of running the transformation code snippet that uses the UpperCaseFunction
class is shown next.
The above code snippets showed methods devoted to filtering and transforming collections’ entries with Guava. The entire code listing for the main class is shown next.
GuavaCollections2.java
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 | package dustin.examples; import static java.lang.System.out; import com.google.common.base.Predicates; import com.google.common.collect.Collections2; import java.util.Collection; import java.util.HashSet; import java.util.Set; /** * Class whose sole reason for existence is to demonstrate Guava's Collections2 * class. * * @author Dustin */ public class GuavaCollections2 { /** * Provides a Set of Strings. * * @return Set of strings representing some programming languages. */ private static Set<String> buildSetStrings() { final Set<String> strings = new HashSet<String>(); strings.add( 'Java' ); strings.add( 'Groovy' ); strings.add( 'Jython' ); strings.add( 'JRuby' ); strings.add( 'Python' ); strings.add( 'Ruby' ); strings.add( 'Perl' ); strings.add( 'C' ); strings.add( 'C++' ); strings.add( 'C#' ); strings.add( 'Pascal' ); strings.add( 'Fortran' ); strings.add( 'Cobol' ); strings.add( 'Scala' ); strings.add( 'Clojure' ); strings.add( 'Basic' ); strings.add( 'PHP' ); strings.add( 'Flex/ActionScript' ); strings.add( 'JOVIAL' ); return strings; } /** * Demonstrate Guava's Collections2.filter method. Filter String beginning * with letter 'J'. */ public static void demonstrateFilter() { printHeader( 'Collections2.filter(Collection,Predicate): ' J ' Languages' ); final Set<String> strings = buildSetStrings(); out.println( '\nOriginal Strings (pre-filter):\n\t' + strings); final Collection<String> filteredStrings = Collections2.filter(strings, Predicates.containsPattern( '^J' )); out.println( '\nFiltered Strings:\n\t' + filteredStrings); out.println( '\nOriginal Strings (post-filter):\n\t' + strings); } /** * Demonstrate Guava's Collections2.transform method. Transform input * collection's entries to uppercase form. */ public static void demonstrateTransform() { printHeader( 'Collections2.transform(Collection,Function): Uppercase' ); final Set<String> strings = buildSetStrings(); out.println( '\nOriginal Strings (pre-transform):\n\t' + strings); final Collection<String> transformedStrings = Collections2.transform(strings, new UpperCaseFunction<String, String>()); out.println( '\nTransformed Strings:\n\t' + transformedStrings); out.println( '\nOriginal Strings (post-transform):\n\t' + strings); } /** * Print a separation header including the provided text. * * @param headerText Text to be included in separation header. */ private static void printHeader( final String headerText) { out.println( '\n==========================================================' ); out.println( '== ' + headerText); out.println( '==========================================================' ); } /** * Main function for demonstrating Guava's Collections2 class. * * @param arguments */ public static void main( final String[] arguments) { demonstrateFilter(); demonstrateTransform(); } } |
Before concluding this post, there is an important caveat to note here. Both methods defined on the Collections2
class contain warnings in their Javadoc documentation about their use. Both methods provide collections that are considered ‘live views’ of the original collections and thus ‘changes to one affect the other.’ For example, removing an element from a source collection similarly removes it from the transformed collection. The documentation for each method also warns that neither returns a collection that is Serializable or thread-safe even when the source collection was Serializable and/or thread-safe.
Conclusion
Guava makes it easier to filter collections and transform collections’ entries in Java. Although the code may not be as concise as that of Groovy for doing similar things, it beats writing straight Java code without use of Guava’s Collections2
class. Java collections can be filtered with Collections2.filter(Collection,Predicate)
or transformed with Collections2.transform(Collection,Function)
.
Reference: Filtering and Transforming Java Collections with Guava’s Collections2 from our JCG partner Dustin Marx at the Inspired by Actual Events blog.
minimum Guava code much useless java code. Conclusion – shity article. There was published much better, much bigger, much detailed article.