You can check the Google Guava presentation I did for work.
Showing posts with label google. Show all posts
Showing posts with label google. Show all posts
Wednesday, February 12, 2014
Monday, November 22, 2010
google's guava library tutorial part 5: back to the primitive(s)
In the fifth part of my tutorial, I'll try to show you the Primitives package of Google Guava library. Primitives package offers several classes to work on primitives or arrays of primitives which are not found in the corresponding wrapper classes (e.g. Boolean for booleans) or Arrays. I will begin with Ints which's the helper class for int related operations. Although it's open to discussion, int is probably the most used primitive type and most of the helper methods are shared among classes in the Primitives package so when I explain Ints, I cover the majority of the methods in the Primitives package.
There are two cast methods in Ints for casting long to int. The first one, saturatedCast(), returns the nearest int value to the given long.
You'll probably use saturatedCast in cases where using the approximated value wont cause you any problems. In cases you can't take that risk you should use checkedCast(). In cases where you try to cast a long out of int range this method will throw you IllegalArgumentException.
You will get java.lang.IllegalArgumentException: Out of range: 2147483648 (which's max int value + 1)
min() (max()) returns smallest (largest) integer in the integer array. Collections class has similar min/max methods but it was not straightforward to transform an int array to a Collection.
If you have a sorted int array in hand you better use Arrays.binarySearch() if not then use Ints.indexOf().
You can see the use of join() method. You just give a String separator and an int array for obtaining a string presentation of each element separated by the given separator.
There's no good alternative to this without Guava as far as I know. Its not straightforward to convert the int[] to a List so you can call toString() for obtaining a string presentation of int array. You can't use Joiner class either because it's for working on objects rather than primitives.
There's also a lastIndex() method which returns the index of the last occurrence of the given integer
indexOf() starts from the beginning and check each element while lastIndexOf() starts from the end. If you just need if the element in hand is part of the given array or not (instead of its place in the array) then you can use contains().
concat() concats the given int arrays. Ints.concat({a, b}, {c,d}) will return {a, b, c, d}. One of the old ways of doing this was creating an int array with the sum size of the given arrays and copy their content in the new array by either iterating over them or by using System.arraycopy().
There's a compare() method for comparing two integers. compare(x, y) returns a negative value if x is less than y, a positive value if x is greater than y or zero if they are equal which means that it works the way Integer's compareTo() works.
Assume that I have a Collection of Integers like below and I want an int array from this collection.
ensureCapacity() returns the given array directly if arrays size is more than the given min length. Else it returns a new array of length (min length+padding) and copies the given array to the newly create array. Extra elements in the new array are given default initialization values. e.g. 0 for int, false for boolean.
Ints can hand you a Comparator for comparing int arrays. First I create a List of int arrays. I'll sort them so you can see how the lexicographic comparison works
Empty array is the first as you can see. When one element is the prefix of the other the shorter one is first (as in the case of 1 and 1-5-0).
You can obtain a live view of the array in hand as a List using asList(). Operations that'll cause a problem in the array wont be supported by the List in hand. Updates are bi-directional which means that if you change the live List view the array changes too, and vice versa.
You can't add or remove an element to the backing list. This operation will throw you java.lang.UnsupportedOperationException. This restriction is probably due to the fact that the underlying data structure is an array which is in fact fixed-sized thus you cant add or remove elements to/from it.
Set operation will work indeed. See the change in the underlying array.
There are few byte-related method that I chose to skip. If you're interested in them please check the javadoc. This is all for Ints class.
The methods I showed were identical for most of this package's classes (Booleans, Chars, Doubles, Floats, Longs, Shorts, Bytes). Now I'll try to explain the methods that are interesting and not covered.
When working with bytes you can be indifferent to their sign (Bytes) or choose to use signed bytes (SignedBytes) or unsigned bytes (UnsignedBytes). All these classes contain methods which are already covered. Only UnsignedBytes is worth mentioning.
Each negative byte is mapped to a positive one in this class. A negative byte b is treated as 256 + b. toInt() is the only method that's not previously covered.
Primitives class is a helper class for working on primitive or wrapper classes. allPrimitiveTypes() returns the Set of primitive types' classes. allWrapperTypes() returns the Set of wrapper types. isWrapperType() checks if the given class is a wrapper type. unwrap() returns the given wrapper class' primitive while wrap() does the inverse.
This is all for the Primitives package. Although I think that some of the methods are redundant there are quite useful ones that'll make your life much easier.
There are two cast methods in Ints for casting long to int. The first one, saturatedCast(), returns the nearest int value to the given long.
// max value of long is too large for int
// thus it'll cast to the nearest int
// which's the max int value
int saturatedCast = Ints.saturatedCast(Long.MAX_VALUE);
System.out.println(saturatedCast);
//2147483647
System.out.println(saturatedCast == Integer.MAX_VALUE); // true
// min value of long is too small for int
// thus it'll cast to the nearest int
// which's the min int value
saturatedCast = Ints.saturatedCast(Long.MIN_VALUE);
System.out.println(saturatedCast);
//-2147483648
System.out.println(saturatedCast == Integer.MIN_VALUE); // true
// 0 is available in int range [-2147483648, 2147483647]
// so the nearest value to cast
// is itself in int
saturatedCast = Ints.saturatedCast(0L);
System.out.println(saturatedCast);
System.out.println(saturatedCast == 0); // true
You'll probably use saturatedCast in cases where using the approximated value wont cause you any problems. In cases you can't take that risk you should use checkedCast(). In cases where you try to cast a long out of int range this method will throw you IllegalArgumentException.
long long1 = Integer.MAX_VALUE;
long1++;
int checkedCast = Ints.checkedCast(long1);
System.out.println(checkedCast);
You will get java.lang.IllegalArgumentException: Out of range: 2147483648 (which's max int value + 1)
min() (max()) returns smallest (largest) integer in the integer array. Collections class has similar min/max methods but it was not straightforward to transform an int array to a Collection.
int[] integerArray = new int[]{3, 5, 7, -3};
System.out.println("Max: "+ Ints.max(integerArray) ); // 7
System.out.println("Min: "+ Ints.min(integerArray) ); // -3
// There are two indexOf methods
// if we dont count lastIndexOf()
// The first one finds the index of the given integer
// in the given array
int indexOf = Ints.indexOf(integerArray, 7);
System.out.println("index of "+7+" in "+Ints.asList(integerArray)+" is "+indexOf);
// index of 7 in [3, 5, 7, -3] is 2
// The second one finds the beginning index of the second
// given array
// in the first given array
indexOf = Ints.indexOf(integerArray, new int[]{7, -3});
System.out.println("index of the given array in "+Ints.join(",", integerArray)+" is "+indexOf);
// index of the given array in 3,5,7,-3 is 2
// If it couldnt find the given value
// it returns -1
indexOf = Ints.indexOf(integerArray, 6);
System.out.println("index of "+6+" in "+Ints.join(",", integerArray)+" is "+indexOf);
// index of 6 in [3, 5, 7, -3] is -1
If you have a sorted int array in hand you better use Arrays.binarySearch() if not then use Ints.indexOf().
You can see the use of join() method. You just give a String separator and an int array for obtaining a string presentation of each element separated by the given separator.
System.out.println(Ints.join("|", new int[]{3, 4, 5, 6, 2, 7}));
//output: 3|4|5|6|2|7
There's no good alternative to this without Guava as far as I know. Its not straightforward to convert the int[] to a List
There's also a lastIndex() method which returns the index of the last occurrence of the given integer
int[] newIntArray = new int[]{5, 23, 6, 24, 69, 6};
int lastIndexOf = Ints.lastIndexOf(newIntArray, 6);
System.out.println("Last index of: "+lastIndexOf);
// Last index of: 5
System.out.println(lastIndexOf == (newIntArray.length-1));
// 6 is the last element so this returns true
indexOf() starts from the beginning and check each element while lastIndexOf() starts from the end. If you just need if the element in hand is part of the given array or not (instead of its place in the array) then you can use contains().
System.out.println("Is there 69 in the array? "+Ints.contains(newIntArray, 69));
//true
System.out.println("Is there 66 in the array? "+Ints.contains(newIntArray, 66));
//false
concat() concats the given int arrays. Ints.concat({a, b}, {c,d}) will return {a, b, c, d}. One of the old ways of doing this was creating an int array with the sum size of the given arrays and copy their content in the new array by either iterating over them or by using System.arraycopy().
int[] concatResult = Ints.concat(new int[]{1, 2, 3, 4, 5, 6, 7},
new int[]{8, 9, 10}, new int[]{11, 12, 13, 14});
System.out.println(Ints.join("|", concatResult));
// 1|2|3|4|5|6|7|8|9|10|11|12|13|14
There's a compare() method for comparing two integers. compare(x, y) returns a negative value if x is less than y, a positive value if x is greater than y or zero if they are equal which means that it works the way Integer's compareTo() works.
System.out.println(Ints.compare(2, 4)); // -1
System.out.println(Ints.compare(5, 3)); // 1
System.out.println(Ints.compare(3, 3)); // 0
Assume that I have a Collection of Integers like below and I want an int array from this collection.
ListintegerList =
Lists.newArrayList(new Integer(0), new Integer(2), new Integer(-8));
// integerList.toArray() will give me an array of Integers.
// What if I'd prefer an array of int and not Integer?
int[] array = Ints.toArray(integerList);
System.out.println(Ints.join(", ", array));
// 0, 2, -8
ensureCapacity() returns the given array directly if arrays size is more than the given min length. Else it returns a new array of length (min length+padding) and copies the given array to the newly create array. Extra elements in the new array are given default initialization values. e.g. 0 for int, false for boolean.
int[] myIntegerArray = new int[]{1, 4, 5, 7, 3, 2};
int[] ensureCapacity =
Ints.ensureCapacity(myIntegerArray, 4, 3);
// len=4, padding=3
System.out.println(Ints.join(", ", ensureCapacity));
// the same array is returned
System.out.println(myIntegerArray == ensureCapacity);
// true
int[] ensureCapacity2 =
Ints.ensureCapacity(myIntegerArray, 10, 3);
// len=10, padding=3
System.out.println(Ints.join(", ", ensureCapacity2));
// a new array is returned with 0s at the end
System.out.println(ensureCapacity2.length == (10+3));
// true because the size is len+padding
Ints can hand you a Comparator for comparing int arrays. First I create a List of int arrays. I'll sort them so you can see how the lexicographic comparison works
ArrayList < int[] > newArrayList =
Lists.newArrayList( new int[]{1}, new int[]{2},
new int[]{1, 5, 0}, new int[]{2, 5, 0},
new int[]{2, 1}, new int[]{}, new int[]{2, 5, 1},
new int[]{2, 5});
// Sort the collection in hand
Collections.sort(newArrayList, Ints.lexicographicalComparator());
// I do a transformation to see the String presentation
List < String > transform5 = Lists.transform(newArrayList, new Function < int[], String >(){
@Override
public String apply(int[] array) {
return Ints.join("-", array);
}});
System.out.println("lexicographicalComparator: "+ transform5);
// lexicographicalComparator: [, 1, 1-5-0, 2, 2-1, 2-5, 2-5-0, 2-5-1]
Empty array is the first as you can see. When one element is the prefix of the other the shorter one is first (as in the case of 1 and 1-5-0).
You can obtain a live view of the array in hand as a List using asList(). Operations that'll cause a problem in the array wont be supported by the List in hand. Updates are bi-directional which means that if you change the live List view the array changes too, and vice versa.
int[] integerArray2 = new int[]{1, 4, 6, 7};
List < Integer > newIntegerList = Ints.asList(integerArray2);
You can't add or remove an element to the backing list. This operation will throw you java.lang.UnsupportedOperationException. This restriction is probably due to the fact that the underlying data structure is an array which is in fact fixed-sized thus you cant add or remove elements to/from it.
// newIntegerList.add(66);
// newIntegerList.remove(0);
// newIntegerList.clear();
Set operation will work indeed. See the change in the underlying array.
// {1, 4, 6, 7}
newIntegerList.set(0, 2); // put 2 in the zeroth place
System.out.println("set(): "
+Ints.join(", ", integerArray2));
//set(): 2, 4, 6, 7
System.out.println("set(): "
+newIntegerList); // set(): [2, 4, 6, 7]
// Now lets change something from the array.
// See the change in the list
integerArray2[0] = 99;
System.out.println("set [0]: "
+Ints.join(", ", integerArray2)); //set [0]: 99, 4, 6, 7
System.out.println("set [0]: "
+newIntegerList); //set [0]: [99, 4, 6, 7]
There are few byte-related method that I chose to skip. If you're interested in them please check the javadoc. This is all for Ints class.
The methods I showed were identical for most of this package's classes (Booleans, Chars, Doubles, Floats, Longs, Shorts, Bytes). Now I'll try to explain the methods that are interesting and not covered.
When working with bytes you can be indifferent to their sign (Bytes) or choose to use signed bytes (SignedBytes) or unsigned bytes (UnsignedBytes). All these classes contain methods which are already covered. Only UnsignedBytes is worth mentioning.
Each negative byte is mapped to a positive one in this class. A negative byte b is treated as 256 + b. toInt() is the only method that's not previously covered.
int int1 = UnsignedBytes.toInt((byte)-125);
// 256 - 125 = 131
System.out.println(int1 == 131); // true
Primitives class is a helper class for working on primitive or wrapper classes. allPrimitiveTypes() returns the Set of primitive types' classes. allWrapperTypes() returns the Set of wrapper types. isWrapperType() checks if the given class is a wrapper type. unwrap() returns the given wrapper class' primitive while wrap() does the inverse.
Set < Class > > allPrimitiveTypes =
Primitives.allPrimitiveTypes();
System.out.println(
"All primitive types: "+allPrimitiveTypes);
// All primitive types:
// [byte, boolean, void, int, long, short, double, char, float]
Set < Class > > allWrapperTypes = Primitives.allWrapperTypes();
System.out.println("All wrapper types: "+allWrapperTypes);
// All wrapper types: [class java.lang.Byte, class java.lang.Short,
// class java.lang.Float, class java.lang.Character, class java.lang.Long,
// class java.lang.Integer, class java.lang.Boolean, class java.lang.Void, class java.lang.Double]
System.out.println(Primitives.isWrapperType(int.class));
// false because int is not a wrapper type
System.out.println(Primitives.isWrapperType(Integer.class));
// true because Integer is a wrapper type
System.out.println(Primitives.isWrapperType(Object.class));
// false because Object is not a wrapper type
// As I have a set of wrapper types
// I can check if a class is
// a wrapper type or a primitive type.
System.out.println("is wrapper? "+Primitives.allWrapperTypes().contains(Integer.class));
// true
System.out.println("is primitive? "+Primitives.allPrimitiveTypes().contains(int.class));
// true
//both below are true because if I unwrap an Integer
// I obtain an int and if I wrap an int I obtain
// an Integer
System.out.println(
Primitives.unwrap(Integer.class).equals(int.class));
System.out.println(
Primitives.wrap(int.class).equals(Integer.class));
This is all for the Primitives package. Although I think that some of the methods are redundant there are quite useful ones that'll make your life much easier.
Thursday, August 12, 2010
google's guava library tutorial part 4: taste the functional programming flavor in java with predicates
In this blog entry, I'll try to explain another functional programming feature introduced by Google Guava library: Predicates. They work like the Function class with the difference that they just return a boolean value. It's possible to use Predicates for filtering elements in an Iterable that satisfy the given Predicate or to check if all/any element in an Iterable satisfies the given Predicate.
Lets write a Predicate that accepts Person objects with names that began with a vowel letter. But first, let me show you what's Person object.
Now lets see what a Predicate looks like;
Now lets build a Person set and begin working using it.
filter() will use our Predicate and create a view from elements that satisfy the
Predicate
As you can see the removal of an item from the view causes the same removal from the origin set. This removal action is bidirectional. e.g. removal from the origin set will remove the corresponding element from the view.
Lets see what happens when I add to the original list.
The view is updated as well and the elements that are accepted by the predicate are added to the view. In the case above only alex is accepted. you can try add a new element to the view which does not met the predicate's requirement.
The commented line above will throw java.lang.IllegalArgumentException because the view does not accept elements that does not met the predicate's requirement.
The filter() method can be called from Iterables for all Iterable objects. All live-view tricks we saw earlier are still valid. But what I'll do for working on Maps? It's possible to filter Map objects using keys or values or both (entries) as input. First, I will build a game characters to appearance map.
Now lets create the necessary Predicates. I'd like to have game characters with 'o' in their name and with lots of game appearances (more than 10 to be exact).
First we will filter using the names (keys) and then we will filter using the number of appearances (values).
You can obtain the desired map by writing a single Predicate that will contain both predicates and use this Predicate on entries of a Map. It's not possible for Predicates.and() because we have to apply the Predicate on both keys and values but new Predicate built using and() can only be applied on keys or values. Lets create a new Predicate for our case.
Functions class has a static method that'll convert your Predicate to a Function. The said Function will use your Predicate and return the result as a Boolean.
CharMatcher is basically a Predicate who accepts Character (instead of objects). Due to this fact you can easily convert your Predicate to a CharMatcher. Lets assume that we have a Predicate that allows vowels only.
With forPredicate() we can build a CharMatcher from a Predicate. Lets use our new CharMatcher for counting vowels in a String.
Predicates class contains several useful methods for creating Predicates. If you plan using Predicates you should take a look. Lets see its methods.
Assume that we don't want people with long last names. Our character limit can be 8 for instance. Lets write a Predicate for the purpose.
Because Skywalker is more than 7 characters it's filtered out. All other last names are in line with the predicate but what if I want a more complicated Predicate? For instance one which will accept people with first name that begins with a vowel and with short last name. I can combine 2 Predicates in this case.
We know that longer last names will return false and we will be left with shorter last names. e.g. [Bilbo Baggins, Alex Delarge, Sezin Karli, Frodo Baggins].Then we will apply the vowel Predicate which will give [Alex Delarge] because Alex is the only first name that begins with a vowel. All Predicates that are combined will be applied for each element in the Iterable (Set, here). If one of the Predicates are false then the overall result is false else it will return true.
There are three and() methods. We show the one that'll work with 2 Predicates. There's a version that'll work with more than 2 Predicates (var-arg as argument). The last one takes Predicates from an Iterable that contains them (Iterable ). We previously used the boolean and() operator. It's also possible to combine Predicates with or() operator. or() will return true even one of the results is true if none is true then it'll return false. Assume that I want either short first names or short last names. I have a Predicate for last names. Lets add a new one for first names.
It's possible to negate the Predicate in hand using not() method. Lets negate the combined predicate we created using and(). Normally we are accepting people with first name that begins with a vowel and with short last name. If we negate this the Predicate will accept people with first name that begin with a consonant and with a long last name.
Anakin is the only one with a vowel in the first name but as his last name is long he's allowed by the Predicate.
You can create two interesting Predicates using isNull() and notNull(). isNull() (notNull()) returns a Predicate that returns true if the object in hand is null (not null).
As you can see the null value is not present in the new view Set.
It's possible to use Predicates' contains() or containsPattern() methods for building a Predicate that'll accept only CharSequences that contain the given pattern. contains() takes a Pattern object while containsPattern() takes a regular expression as a String.
Another useful method of Predicates is in(). It allows elements that are inside a given Collection and rejects all others.
Predicates' instanceOf() checks if the object in hand is an instance of the given Class.
Only instances of List are allowed so the result contains only the ArrayList and LinkedList.
Another interesting method of Predicates is compose(). compose() method allows you to process all your elements using the given Function and apply a Predicate on the result. You can do that in 2 steps but when you can do that in a single step do you need it? I have a set of objects of type Circle. I'd like to filter Circles with their area less than a value. It's possible do the calculation of the area in the Predicate or we can put the method in a helper class (e.g. Circles.getArea()). Another possibility is to write a Function for this operation.
Each circle is first processed by calculateArea Function and their areas are obtained. Then allowCirclesWithLargeArea Predicate can be used for filtering the areas in hand.
Iterables class contains several methods for working using Predicates. all() and any() are quite straightforward as methods. all (any) returns true if all (any) elements in the given Iterable satisfy the given Predicate. I'm going to create Band class for storing two attributes of a Band (its name and country of origin). Then create a country Predicate so we can see what all() and any() do.
Now lets create the bands.
Lets remove all bands form Finland and see any()s behavior. There are more than one way to do that. The most straightforward way is to use removeIf() method of Iterables class which removes elements that satisfy the given Predicate from the given Iterable.
Iterables' filter() method can be used for filtering any Iterable using Predicates. It's similar to Collections2's filter method but usable for a larger number of Classes.
Iterables class has two more interesting methods. indexOf() which returns the index of the first element that satisfies the given Predicate. If it cant find a matching element it returns -1. The other method is find() which returns the first element which satisfies the given Predicate. If it cant find a matching element it throws NoSuchElementException. To sum up find() returns the object, indexOf() returns its index in the Iterable. As find() throws an exception in the case it couldnt find a matching element it would be wise to check first with indexOf() and then either use the index to obtain the object or to use find().
This is all for the Predicates. I hope I was able to give you a taste of functional programming in Java using Guava.
Lets write a Predicate that accepts Person objects with names that began with a vowel letter. But first, let me show you what's Person object.
class Person implements Comparable < Person > {
public Person(String name, String lastName){
this.name = name;
this.lastName = lastName;
}
public Person(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
private String name;
private String lastName;
@Override
public int compareTo(Person arg0) {
return this.getName().compareTo(arg0.getName());
}
@Override
public String toString() {
return this.name+" "+this.lastName;
}
}
Now lets see what a Predicate looks like;
Predicate < Person > allowNamesWithVowels = new Predicate < Person > (){
String[] vowels = { "a", "e", "i", "o", "u", "y" };
@Override
public boolean apply(Person person) {
String firstName = person.getName().toLowerCase();
// convert to lowercase just in case
// for each vowel check if
// first name begins with that
// vowel
for(String vowel : vowels){
if(firstName.startsWith(vowel))
return true;
}
return false;
}
};
Now lets build a Person set and begin working using it.
Person frodo = new Person("Frodo", "Baggins");
Person sezin = new Person("Sezin", "Karli");
Person luke = new Person("Luke", "Skywalker");
Person anakin = new Person("Anakin", "Skywalker");
Person eric = new Person("Eric", "Draven");
HashSetsetOfPerson =
Sets.newHashSet( eric, frodo, sezin, luke, anakin );
System.out.println("set of person: "+setOfPerson);
// [Sezin Karli, Luke Skywalker, Anakin Skywalker, Frodo Baggins]
filter() will use our Predicate and create a view from elements that satisfy the
Predicate
Set < Person > view = Sets.filter(setOfPerson, allowNamesWithVowels);
System.out.println("view: "+view);
// filter: [Eric Draven, Anakin Skywalker]
// we remove eric from the view
view.remove(eric);
System.out.println("new view: "+view);
//new view: [Anakin Skywalker]
System.out.println("set of person: "+setOfPerson);
// [set of person: [Sezin Karli, Luke Skywalker, Anakin Skywalker, Frodo Baggins]
As you can see the removal of an item from the view causes the same removal from the origin set. This removal action is bidirectional. e.g. removal from the origin set will remove the corresponding element from the view.
Lets see what happens when I add to the original list.
Person bilbo = new Person("Bilbo", "Baggins");
Person alex = new Person("Alex", "Delarge");
setOfPerson.add(bilbo);
setOfPerson.add(alex);
System.out.println("new view: "+view);
// new view: [Anakin Skywalker, Alex Delarge]
The view is updated as well and the elements that are accepted by the predicate are added to the view. In the case above only alex is accepted. you can try add a new element to the view which does not met the predicate's requirement.
Person jarjar = new Person("Jarjar", "Binks");
//view.add(jarjar);
The commented line above will throw java.lang.IllegalArgumentException because the view does not accept elements that does not met the predicate's requirement.
The filter() method can be called from Iterables for all Iterable objects. All live-view tricks we saw earlier are still valid. But what I'll do for working on Maps? It's possible to filter Map objects using keys or values or both (entries) as input. First, I will build a game characters to appearance map.
Map < String, Integer > characterAppearancesMap = Maps.newHashMap();
characterAppearancesMap.put("Mario", 15);
characterAppearancesMap.put("Snake", 8);
characterAppearancesMap.put("Kratos", 4);
Now lets create the necessary Predicates. I'd like to have game characters with 'o' in their name and with lots of game appearances (more than 10 to be exact).
Predicate < String > allowNamesWithO = new Predicate < String > (){
@Override
public boolean apply(String name) {
String lowerCaseName = name.toLowerCase();
return lowerCaseName.contains("o");
}
};
Predicate < Integer > allowLotsOfAppearances = new Predicate < Integer > (){
@Override
public boolean apply(Integer appearance) {
int numberOfAppearance = appearance.intValue();
return (numberOfAppearance > 10);
}
};
First we will filter using the names (keys) and then we will filter using the number of appearances (values).
Map < String, Integer > filterKeys =
new HashMap < String, Integer > ( Maps.filterKeys(characterAppearancesMap, allowNamesWithO) );
// I copy the live view
System.out.println("Game Characters with 'o' in their name: "+filterKeys);
// {Mario=15, Kratos=4}
Map < String, Integer > filterValues = Maps.filterValues(filterKeys, allowLotsOfAppearances);
System.out.println(
"Game Characters with 'o' in their name and with more than 10 appearances: "+filterValues);
//{Mario=15}
You can obtain the desired map by writing a single Predicate that will contain both predicates and use this Predicate on entries of a Map. It's not possible for Predicates.and() because we have to apply the Predicate on both keys and values but new Predicate built using and() can only be applied on keys or values. Lets create a new Predicate for our case.
Predicate < Map.Entry < String, Integer > > characterPredicate =
new Predicate < Map.Entry < String, Integer > > (){
@Override
public boolean apply(Entryentry) {
String key = entry.getKey();
int value = entry.getValue().intValue();
return (key.contains("o") && value > 10);
}
};
Map < String, Integer > filterEntries =
Maps.filterEntries(characterAppearancesMap, characterPredicate);
System.out.println("Are the game character results same? "+filterEntries.equals(filterValues));
// As you can see the result is the same
Functions class has a static method that'll convert your Predicate to a Function. The said Function will use your Predicate and return the result as a Boolean.
Function < Person, Boolean > vowelVerifier = Functions.forPredicate(allowNamesWithVowels);
ArrayList < Person > people = Lists.newArrayList(anakin, bilbo, alex);
Listtransform2 = Lists.transform(people, vowelVerifier);
// Vowel verifier will return TRUE (FALSE) for each
// person with TRUE (FALSE) Predicate result
System.out.println("Result: "+transform2);
//[true, false, true]
// anakin and alex are true because the Predicate
// was checking to see if the first name of the Person
// begins with a vowel
CharMatcher is basically a Predicate who accepts Character (instead of objects). Due to this fact you can easily convert your Predicate to a CharMatcher. Lets assume that we have a Predicate
Predicate < Character > allowVowel = new Predicate < Character > (){
char[] vowels = { 'a', 'e', 'i', 'o', 'u', 'y' };
@Override
public boolean apply(Character character) {
char lowerCase = Character.toLowerCase(character.charValue());
for(char chr : vowels){
if(chr == lowerCase)
return true;
}
return false;
}
};
With forPredicate() we can build a CharMatcher from a Predicate. Lets use our new CharMatcher for counting vowels in a String.
CharMatcher vowelMatcher = CharMatcher.forPredicate(allowVowel);
int vowelCount = vowelMatcher.countIn("starkiller");
System.out.println("Vowel Count in 'starkiller': "+vowelCount);
Predicates class contains several useful methods for creating Predicates. If you plan using Predicates you should take a look. Lets see its methods.
Assume that we don't want people with long last names. Our character limit can be 8 for instance. Lets write a Predicate for the purpose.
Predicate < Person > allowShortLastNames =
new Predicate < Person > (){
@Override
public boolean apply(Person person) {
String lastName = person.getLastName();
return (lastName.length() < 8);
}
};
System.out.println(setOfPerson);
// [Alex Delarge, Frodo Baggins, Anakin Skywalker,
// Luke Skywalker, Bilbo Baggins, Sezin Karli]
SetonlyShortLastNames =
Sets.filter(setOfPerson, allowShortLastNames);
System.out.println(
"People with short last names: "+onlyShortLastNames);
//[Sezin Karli, Alex Delarge, Bilbo Baggins, Frodo Baggins]
Because Skywalker is more than 7 characters it's filtered out. All other last names are in line with the predicate but what if I want a more complicated Predicate? For instance one which will accept people with first name that begins with a vowel and with short last name. I can combine 2 Predicates in this case.
Predicate < Person > combinedPredicates =
Predicates.and(allowShortLastNames, allowNamesWithVowels );
Set < Person > filter = Sets.filter(setOfPerson, combinedPredicates);
System.out.println("Combined Predicates: "+filter);
// Alex Delarge
We know that longer last names will return false and we will be left with shorter last names. e.g. [Bilbo Baggins, Alex Delarge, Sezin Karli, Frodo Baggins].Then we will apply the vowel Predicate which will give [Alex Delarge] because Alex is the only first name that begins with a vowel. All Predicates that are combined will be applied for each element in the Iterable (Set, here). If one of the Predicates are false then the overall result is false else it will return true.
There are three and() methods. We show the one that'll work with 2 Predicates. There's a version that'll work with more than 2 Predicates (var-arg as argument). The last one takes Predicates from an Iterable that contains them (Iterable
Predicate < Person > allowShortFirstNames = new Predicate < Person > (){
@Override
public boolean apply(Person person) {
String firstName = person.getName();
return (firstName.length() < 8);
}
};
Predicate < Person > predicatesCombinedWithOr =
Predicates.or(allowShortLastNames, allowShortFirstNames);
filter = Sets.filter(setOfPerson, predicatesCombinedWithOr);
System.out.println(setOfPerson);
System.out.println("Combined with or:"+filter);
// As you can see nothing is filtered because
// setOfPerson elements have either short
// first names or short last names
// Lets add a person with a long first name
// and last name
setOfPerson.add(new Person("Abdullah", "Jabbarian"));
filter = Sets.filter(setOfPerson, predicatesCombinedWithOr);
System.out.println("Combined with or 2: "+filter);
// [Alex Delarge, Frodo Baggins, Anakin Skywalker,
// Luke Skywalker, Bilbo Baggins, Sezin Karli]
// As you can see Abdullah who has a long first and last name
// is not in the new set.
It's possible to negate the Predicate in hand using not() method. Lets negate the combined predicate we created using and(). Normally we are accepting people with first name that begins with a vowel and with short last name. If we negate this the Predicate will accept people with first name that begin with a consonant and with a long last name.
PredicatenegatedPredicates =
Predicates.not(combinedPredicates);
//Alex delarge was the only person with the predicate in hand.
//When we negate the predicate
//we will get a predicate that will return
//every element but alex delarge
filter = Sets.filter(setOfPerson, negatedPredicates);
System.out.println("Negated and combined Predicates: "+filter);
// [Frodo Baggins, Anakin Skywalker, Abdullah Jabbarian,
// Luke Skywalker, Bilbo Baggins, Sezin Karli]
Anakin is the only one with a vowel in the first name but as his last name is long he's allowed by the Predicate.
You can create two interesting Predicates using isNull() and notNull(). isNull() (notNull()) returns a Predicate that returns true if the object in hand is null (not null).
setOfPerson.add(null);
System.out.println(setOfPerson);
//[null, Alex Delarge, Frodo Baggins, Anakin Skywalker,
// Abdullah Jabbarian, Luke Skywalker, Bilbo Baggins, Sezin Karli]
Predicate < Person > notNullPredicate = Predicates.notNull();
// this predicate will return true if and
// only if the Person in hand is not null
Set < Person > filter2 = Sets.filter(setOfPerson, notNullPredicate);
System.out.println(filter2);
//[Alex Delarge, Frodo Baggins, Anakin Skywalker,
//Abdullah Jabbarian, Luke Skywalker, Bilbo Baggins, Sezin Karli]
As you can see the null value is not present in the new view Set.
It's possible to use Predicates' contains() or containsPattern() methods for building a Predicate that'll accept only CharSequences that contain the given pattern. contains() takes a Pattern object while containsPattern() takes a regular expression as a String.
// the Predicate below only accepts words with a number inside
Predicate < CharSequence > containsPattern =
Predicates.containsPattern("[0-9]");
Setsw = Sets.newHashSet("r2-d2", "luke", "c3po", "darth");
Setfilter3 = Sets.filter(sw, containsPattern);
System.out.println("New set of sw characters "+filter3);
// contains and containsPattern are similar
Predicate < CharSequence > containsPattern2 =
Predicates.contains( Pattern.compile("[0-9]") );
Set < String > filter4 = Sets.filter(sw, containsPattern2);
System.out.println("Do they have the same result? "+filter4.equals(filter3));
Another useful method of Predicates is in(). It allows elements that are inside a given Collection and rejects all others.
ArrayList < String > fruitList =
Lists.newArrayList("apple", "melon", "strawberry");
Predicate < String > fruitPredicate = Predicates.in(fruitList);
List < String > fruitBasket =
Lists.newArrayList("apple", "mango", "melon", "banana", "apple", "melon", "strawberry", "melon", "strawberry");
Iterable < String > filter5 = Iterables.filter(fruitBasket, fruitPredicate);
// As Lists does not have a filter method I used from Collections2
System.out.println("Filtered Fruit Basket: "+filter5);
// Filtered Fruit Basket: [apple, melon, apple,
// melon, strawberry, melon, strawberry]
// only 3 types of fruits are left as you can see
// If you dont need a live view you can easily use retainAll()
// for both List and Set which has a similar effect.
fruitBasket.retainAll(fruitList);
System.out.println("Filtered Fruit Basket: "+fruitBasket);
Predicates' instanceOf() checks if the object in hand is an instance of the given Class.
Predicate < Object > listPredicate = Predicates.instanceOf(List.class);
List < Collection < collectionsList =
new ArrayList < Collection > ();
collectionsList.add(new HashSet());
collectionsList.add(new ArrayList());
collectionsList.add(new LinkedList());
collectionsList.add(new TreeSet());
collectionsList.add(new LinkedHashSet());
Collection < Collection > filter6 =
Collections2.filter(collectionsList, listPredicate);
System.out.println("Are only Lists filtered? "
+ (filter6.size() == 2) );
// only two elements are allowed
Only instances of List are allowed so the result contains only the ArrayList and LinkedList.
Another interesting method of Predicates is compose(). compose() method allows you to process all your elements using the given Function and apply a Predicate on the result. You can do that in 2 steps but when you can do that in a single step do you need it? I have a set of objects of type Circle. I'd like to filter Circles with their area less than a value. It's possible do the calculation of the area in the Predicate or we can put the method in a helper class (e.g. Circles.getArea()). Another possibility is to write a Function for this operation.
Function < Circle, Double > calculateArea =
new Function < Circle, Double > () {
@Override
public Double apply(Circle circle) {
double radius = circle.getRadius();
double area = Math.PI * radius * radius;
return area;
}
};
Predicate < Double > allowCirclesWithLargeArea =
new Predicate < Double > () {
double value = 10d;
@Override
public boolean apply(Double area) {
return area > value;
}
};
Predicate < Circle > allowCircles =
Predicates.compose(allowCirclesWithLargeArea, calculateArea);
HashSet < Circle > circleSet =
Sets.newHashSet( new Circle(3.5, 4.5, 0.3),
new Circle(2.5, 1.5, 0.03), new Circle(3.4, 4.6, 4.3),
new Circle(3.5, 6.5, 5.3), new Circle(0.5, 4.5, 12.3));
Set < Circle > filter7 =
Sets.filter(circleSet, allowCircles);
System.out.println(
"Allow circle with area less than 10: "+filter7);
// output: Allow circle with area less than 10:
//[{x=0.5, y=4.5, radius=12.3},
// {x=3.5, y=6.5, radius=5.3},
//{x=3.4, y=4.6, radius=4.3}]
Each circle is first processed by calculateArea Function and their areas are obtained. Then allowCirclesWithLargeArea Predicate can be used for filtering the areas in hand.
Iterables class contains several methods for working using Predicates. all() and any() are quite straightforward as methods. all (any) returns true if all (any) elements in the given Iterable satisfy the given Predicate. I'm going to create Band class for storing two attributes of a Band (its name and country of origin). Then create a country Predicate so we can see what all() and any() do.
class Band{
String name, country;
public Band(String name, String country) {
this.name = name;
this.country = country;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
@Override
public String toString() {
return "{name= "+name+", country= "+country+"}";
}
}
Now lets create the bands.
Band stratovarius = new Band("Stratovarius", "Finland");
Band amorphis = new Band("Amorphis", "Finland");
Set < Band > metalBands =
Sets.newHashSet(stratovarius, amorphis);
Predicate < Band > finlandPredicate =
new Predicate < Band > () {
@Override
public boolean apply(Band band) {
boolean result =
band.getCountry().equals("Finland");
// is band country Finland?
return result;
}
};
// Easy to predict what I'll do right?
//I have two bands from Finland and a Finland Predicate.
//So all() should return true to me because every band
//is from Finland.
boolean all =
Iterables.all(metalBands, finlandPredicate);
System.out.println(
"every band is from Finland? "+all); // TRUE
// Lets add Mezarkabul to the band set
// With this addition not every element
// satisfies the Predicate
Band mezarkabul = new Band("Mezarkabul", "Turkey");
metalBands.add(mezarkabul) ;
all = Iterables.all(metalBands, finlandPredicate);
System.out.println(
"every band is from Finland? "+all); // FALSE
// Still any() should return true because
// at least one element is still satisfying the
// Predicate.
boolean any = Iterables.any(metalBands, finlandPredicate);
System.out.println(
"at least one band is from Finland? "+any);
Lets remove all bands form Finland and see any()s behavior. There are more than one way to do that. The most straightforward way is to use removeIf() method of Iterables class which removes elements that satisfy the given Predicate from the given Iterable.
Iterables.removeIf(metalBands, finlandPredicate);
// you can see that none of the bands are from Finland as of now
System.out.println(metalBands);
// output: [{name= Mezarkabul, country= Turkey}]
//lets see any()'s behavior now
any = Iterables.any(metalBands, finlandPredicate);
System.out.println("at least one band is from Finland? "+any);
Iterables' filter() method can be used for filtering any Iterable using Predicates. It's similar to Collections2's filter method but usable for a larger number of Classes.
Iterables class has two more interesting methods. indexOf() which returns the index of the first element that satisfies the given Predicate. If it cant find a matching element it returns -1. The other method is find() which returns the first element which satisfies the given Predicate. If it cant find a matching element it throws NoSuchElementException. To sum up find() returns the object, indexOf() returns its index in the Iterable. As find() throws an exception in the case it couldnt find a matching element it would be wise to check first with indexOf() and then either use the index to obtain the object or to use find().
metalBands.add(new Band("Lordi", "Finland"));
// returns the index of the
// first element that satisfies
// the predicate which's
// Lordi
if(Iterables.indexOf(metalBands, finlandPredicate) != -1){
// here we are sure that
// such a band exists
Band bandFromFinland =
Iterables.find(metalBands, finlandPredicate);
System.out.println("The first band from Finland: "
+bandFromFinland);
}
This is all for the Predicates. I hope I was able to give you a taste of functional programming in Java using Guava.
Monday, May 17, 2010
google's guava library tutorial part 3: taste the functional programming flavor in java
Java is not a functional programming language but thanks to Google Guava Library
you can incorporate functional programming with it. In the third part of my tutorial I'll talk about Function which's one of the two classes related to the functional programming. The other is the Predicate class.
If you are not familiar to functional programming, I can briefly say that functions are like factories. They accept objects. They work using these objects and they return new and useful objects.
Usual Function definition in Guava contains two generics. The first one is the object type the function accepts, the second one is the object type it returns. The function below will accept a Person object, find the initial of this name and last name, create a StringBuilder containing these initials and return the StringBuilder object.
For the sake of completeness, lets give the Person object that'll be used during the examples.
If you want, you can transform a whole list of Persons (the initial list) to a list of StringBuilders of person name initials (result list) using returnNameInitials function.
Notice that any change in the initial list will result in updates in the obtained list. e.g. if you remove, change, add an element in the initial list you'll see that the corresponding element in the result list will get updated as well. The result list is basically the view of the initial list in hand. Functions work one way (from Person to StringBuilder here), so although it's said (in javadoc) that the updates are bi-directional you can't do much operation in the result (view) list. For instance, you can't add new elements. If I could add "T.P." to the result list, what name and last name will this Person have in the initial list? This information cannot be obtained from the Function we use. You can't change the element content of the result (view) list too. The reason is the same with the previous case. But as you probably guess, removing an element from the result (view) list has no negative impact. Corresponding element in the initial list will be removed as well.
Collections2.transform() is similar to Lists.transform() with the difference that it can work on a larger number of classes. For instance, if you want to transform an HashSet of Person can't do that with Lists' or Sets' methods (though you can do it with Iterable.transform()). All the live view-related stuff is valid for Lists.transform().
Functions' compose() method allowsus to compose functions. if f: A->B and g: B->C then f o g: A->C. The output of the first function will be the input of the second function.
But I have a list of floats, what should I do in this case? I'd like to change the squareOfADouble function but there are previous code that uses it. What if I write a float to double function and compose both functions? First I'll convert float to double, then I'll apply square of a double function.
Functions class contains a number of useful methods. One of them is toStringFunction(). This predefined Function takes each object and returns their toString() result.
There are 2 quite useful methods in Functions for working with Maps.
The first forMap() performs a lookup from the given map and returns the value corresponding to the key in hand.
First "luke@starwars.com" is checked from the map and 1684684684L is returned by the function. Beware that you have to be sure that every element in the initial list is available in the function's map as a key else you'll get IllegalArgumentException.
The other forMap() is more useful if you don't want to check the initial list's validity. If the corresponding key is not found during the lookup then the given value is returned by the function.
Maps class has two interesting methods that work with Functions; uniqueIndex() and transformValues(). The first one's a bit counterintuive but the second one is similar to the transform() methods we saw before.
Maps' uniqueIndex() takes two args: an iterable i and a function f. For each element e in the iterable i, function f is called and the result of f is used as the key to the value e. For the mathematically inclined, a new map of f(e)-e pairs will be built using f() and i.
In the example below, extractNickName extracts nicknames from the names (name in between '') when we call uniqueIndex with this function we will have nicknames as keys and full names as values. The result is an immutable map of nickname=fullname pairs. We will explain immutables at another part of the tutorial.
Lets see the other useful method of Maps; transformValues()
While we were explaining Ordering in part 2 of this tutorial, we skipped an important method because we didn't explain Functions. It's time for onResultOf() of Ordering class. Before the ordering the chosen function is applied to the iterable and then the sorting takes places.
I'd like to sort emails based on their domain name. For the purpose I wrote a Function that'll extract the domain part of an e-mail.
you can incorporate functional programming with it. In the third part of my tutorial I'll talk about Function which's one of the two classes related to the functional programming. The other is the Predicate class.
If you are not familiar to functional programming, I can briefly say that functions are like factories. They accept objects. They work using these objects and they return new and useful objects.
Usual Function definition in Guava contains two generics. The first one is the object type the function accepts, the second one is the object type it returns. The function below will accept a Person object, find the initial of this name and last name, create a StringBuilder containing these initials and return the StringBuilder object.
Function < Person, StringBuilder > returnNameInitials =
new Function < Person, StringBuilder > () {
@Override
public StringBuilder apply(Person person) {
// Sezin Karli
char firstCharOfName = Character.toUpperCase(person.getName().charAt(0)); // S
char firstCharOfLastName = Character.toUpperCase(person.getLastName().charAt(0)); // K
return new StringBuilder(firstCharOfName+
"."+firstCharOfLastName+"."); // S.K.
}
};
For the sake of completeness, lets give the Person object that'll be used during the examples.
class Person implements Comparable < Person > {
private String name;
private String lastName;
public Person(String name, String lastName){
this.name = name;
this.lastName = lastName;
}
public Person(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public int compareTo(Person arg0) {
return this.getName().compareTo(arg0.getName());
}
@Override
public String toString() {
return this.name+" "+this.lastName;
}
}
If you want, you can transform a whole list of Persons (the initial list) to a list of StringBuilders of person name initials (result list) using returnNameInitials function.
// process each Person in personList using
//returnNameInitials function
// return the result as a view of the initial list.
List < Person > personList =
Lists.newArrayList(new Person("sezin", "karli"),
new Person("brad", "delp"));
List < StringBuilder > transform3 =
Lists.transform(personList, returnNameInitials);
System.out.println("Name initials: "+transform3);
// o: Name initials: [S.K., B.D.]
Notice that any change in the initial list will result in updates in the obtained list. e.g. if you remove, change, add an element in the initial list you'll see that the corresponding element in the result list will get updated as well. The result list is basically the view of the initial list in hand. Functions work one way (from Person to StringBuilder here), so although it's said (in javadoc) that the updates are bi-directional you can't do much operation in the result (view) list. For instance, you can't add new elements. If I could add "T.P." to the result list, what name and last name will this Person have in the initial list? This information cannot be obtained from the Function we use. You can't change the element content of the result (view) list too. The reason is the same with the previous case. But as you probably guess, removing an element from the result (view) list has no negative impact. Corresponding element in the initial list will be removed as well.
personList.add(new Person("rick","nielsen"));
//added an element o: [S.K., B.D., R.N.]
System.out.println(transform3);
// R.N. is added so the addition to the initial
// list has an impact on the result list
personList.get(0).setName("tom"); //changed an element content
System.out.println(transform3);
// T.K. becomes M.K. so the update to the initial
// list has an impact on the result list
personList.remove(0);// remove the first element.
//o: [B.D., R.N.]
System.out.println(transform3);
//T.K. is no more so the update to the initial
//list again has an impact on the result list
transform3.remove(0);
System.out.println(personList);
// o: [rick nielsen]. as you can see the
// removal from the result list (view) has an impact
//on the initial list
transform3.get(0).append("B.");
// lets try to change to element content
System.out.println("transform 3: "+transform3);
// o: transform 3: [R.N.]. you cant see the change
//because you cant do updates on the result list
// if you check the initial list
// you'll see no change too
Collections2.transform() is similar to Lists.transform() with the difference that it can work on a larger number of classes. For instance, if you want to transform an HashSet of Person can't do that with Lists' or Sets' methods (though you can do it with Iterable.transform()). All the live view-related stuff is valid for Lists.transform().
Set < Person > personSet =
Sets.newHashSet(new Person("sezin", "karli"),
new Person("brad", "delp"));
Collection < StringBuilder > transform4 =
Collections2.transform(personSet, returnNameInitials);
System.out.println(transform4); // o: [S.K., B.D.]
Functions' compose() method allowsus to compose functions. if f: A->B and g: B->C then f o g: A->C. The output of the first function will be the input of the second function.
//Assume that we used to have a function
//for taking the square of a double.
Function < Double, Double > squareOfADouble =
new Function < Double, Double > () {
@Override
public Double apply(Double double1) {
return double1 * double1;
}
};
But I have a list of floats, what should I do in this case? I'd like to change the squareOfADouble function but there are previous code that uses it. What if I write a float to double function and compose both functions? First I'll convert float to double, then I'll apply square of a double function.
Function < Float, Double > floatToDouble =
new Function < Float, Double > () {
@Override
public Double apply(Float float1) {
return float1.doubleValue();
}
};
// thanks to autoboxing
// float values will be put to Float wrappers.
ArrayList < Float > floatList =
Lists.newArrayList(12.3536343f, 142.3346435633f, 1.44564564f);
// first the second function then the first
// function must be written.
Function < Float, Double > floatToDoubleSquare =
Functions.compose(squareOfADouble, floatToDouble);
List < Double > squareOfFloatsAsDoubles =
Lists.transform(floatList, floatToDoubleSquare);
System.out.println(squareOfFloatsAsDoubles);
// o: [152.61227005628461, 20259.149887098232,
// 2.089891460912341]
Functions class contains a number of useful methods. One of them is toStringFunction(). This predefined Function takes each object and returns their toString() result.
List < Person > newPersonList =
Lists.newArrayList(new Person("sezin", "karli"),
new Person("bilbo", "baggins"));
List < String > toStringList =
Lists.transform(newPersonList, Functions.toStringFunction());
System.out.println(toStringList);
// o: [sezin karli, bilbo baggins]
There are 2 quite useful methods in Functions for working with Maps.
The first forMap() performs a lookup from the given map and returns the value corresponding to the key in hand.
Map < String, Long > emailToEmployeeNo = Maps.newHashMap();
emailToEmployeeNo.put("luke@starwars.com", 1684684684L);
emailToEmployeeNo.put("darth@starwars.com", 245468687687L);
emailToEmployeeNo.put("obiwan@starwars.com", 368684674684L);
Function < String, Long > lookupFunction =
Functions.forMap(emailToEmployeeNo);
ArrayList < String > cantinaVisitOrder =
Lists.newArrayList("luke@starwars.com",
"darth@starwars.com", "obiwan@starwars.com", "luke@starwars.com", "darth@starwars.com");
List < Long > cantinaVisitOrderById =
Lists.transform(cantinaVisitOrder, lookupFunction);
System.out.println("cantina Visit Order By Id: "
+cantinaVisitOrderById);
//cantina Visit Order By Id:
//[1684684684, 245468687687, 368684674684,
// 1684684684, 245468687687]
First "luke@starwars.com" is checked from the map and 1684684684L is returned by the function. Beware that you have to be sure that every element in the initial list is available in the function's map as a key else you'll get IllegalArgumentException.
The other forMap() is more useful if you don't want to check the initial list's validity. If the corresponding key is not found during the lookup then the given value is returned by the function.
Long defaultId = 0L;
Function < String, Long > lookupFunctionWithDefault = Functions.forMap(emailToEmployeeNo, defaultId);
cantinaVisitOrder.add("greedo@starwars.com");
cantinaVisitOrder.add("yoda@starwars.com");
// greedo and yoda visited the cantina
// but they are not in the employee_email=id
// map
System.out.println("cantina visit order by emails: "
+cantinaVisitOrder);
//cantina visit order by emails:
//[luke@starwars.com, darth@starwars.com, obiwan@starwars.com,
// luke@starwars.com, darth@starwars.com,
// greedo@starwars.com, yoda@starwars.com]
List < Long > cantinaVisitOrderById2 =
Lists.transform(cantinaVisitOrder, lookupFunctionWithDefault);
// in the previous forMap() example we would
//take IllegalArgumentException
//for yoda and greedo. now you'll get the defaultId for them
System.out.println("cantina Visit Order By Id 2: "
+cantinaVisitOrderById2);
// as you can see the last 2 employees have 0 as id
//cantina Visit Order By Id 2: [1684684684,
//245468687687, 368684674684, 1684684684, 245468687687, 0, 0]
Maps class has two interesting methods that work with Functions; uniqueIndex() and transformValues(). The first one's a bit counterintuive but the second one is similar to the transform() methods we saw before.
Maps' uniqueIndex() takes two args: an iterable i and a function f. For each element e in the iterable i, function f is called and the result of f is used as the key to the value e. For the mathematically inclined, a new map of f(e)-e pairs will be built using f() and i.
In the example below, extractNickName extracts nicknames from the names (name in between '') when we call uniqueIndex with this function we will have nicknames as keys and full names as values. The result is an immutable map of nickname=fullname pairs. We will explain immutables at another part of the tutorial.
ArrayList < String > characterList =
Lists.newArrayList("Luke 'Blondie' Skywalker",
"Darth 'DarkHelmet' Vader", "Obiwan 'Ben' Kenobi");
Function < String, String > extractNickname =
new Function < String, String > () {
@Override
public String apply(String name) {
//Luke 'Blondie' Skywalker
//as there will be no space in our nicknames
//we can apply the split below
Iterable < String > tokens = Splitter.on(" ").trimResults().split(name);
for(String token : tokens){
// Luke, 'Blondie', Skywalker
if(token.startsWith("'")) //'Blondie'
return token.substring(1, token.length()-1);
// will remove ' in both ends
}
return "none";
}
};
ImmutableMap < String, String > nicknameToNameMap =
Maps.uniqueIndex(characterList, extractNickname);
System.out.println("nicknameToNameMap: "+nicknameToNameMap);
//nicknameToNameMap: {Blondie=Luke 'Blondie' Skywalker,
//DarkHelmet=Darth 'DarkHelmet' Vader, Ben=Obiwan 'Ben' Kenobi}
Lets see the other useful method of Maps; transformValues()
//For the example I write a Function that'll
// extract the username part of an e-mail.
Function < String, String > onlyUsernamePart =
new Function < String, String > () {
@Override
public String apply(String string) { //luke@starwars.com
int index = string.indexOf("@");
return string.substring(0, index); //luke
}
};
//lets create a star wars map with nicknames as
//keys and emails as values
Map < String, String > nicknameToMailMap =
Maps.newHashMap();
nicknameToMailMap.put("luke skywalker", "luke@starwars.com");
nicknameToMailMap.put("darth vader", "vader@starwars.com");
//Function will process the values
Map < String, String > viewMap =
Maps.transformValues(nicknameToMailMap, onlyUsernamePart);
System.out.println(viewMap);
//After the transformation only username part of the emails is left
//{darth vader=vader, luke skywalker=luke}
viewMap.remove("darth vader");
System.out.println(nicknameToMailMap);
// removal on the initial map has an impact on the view as before
//{luke skywalker=luke@starwars.com}
/*
* As Lists.transform() the Maps.transformValues()
* return us a view which's backed by the initial map.
* All view-related stuff is similar with List' transform() method.
* */
While we were explaining Ordering in part 2 of this tutorial, we skipped an important method because we didn't explain Functions. It's time for onResultOf() of Ordering class. Before the ordering the chosen function is applied to the iterable and then the sorting takes places.
I'd like to sort emails based on their domain name. For the purpose I wrote a Function that'll extract the domain part of an e-mail.
Function < String, String > onlyDomainPart =
new Function < String, String > () {
@Override
public String apply(String string) {
//luke@lightside.com
int index = string.indexOf("@");
return string.substring(index);
// lightside.com
}
};
ArrayList < String > usernames =
Lists.newArrayList("luke@lightside.com", "darth@darkside.com", "obiwan@lightside.com", "leia@starwars.com");
// onResultOf() will apply the given Function first
//and do the sort as it's desired.
List < String > sortedCopy8 =
Ordering.natural().onResultOf(onlyDomainPart).
sortedCopy(usernames);
System.out.println(sortedCopy8);
//[darth@darkside.com, luke@lightside.com,
// obiwan@lightside.com, leia@starwars.com]
/*As you can see the usernames list is
ordered based on the domain name
* */
at
21:47
Labels:
compose,
formap,
functional programming,
functions,
google,
guava,
java,
java library,
ordering,
transform,
uniqueindex
Thursday, May 13, 2010
google's guava library tutorial part 2: joys of Ordering
In the first part of my tutorial , I explained anything related to Strings in Guava. In this part of my tutorial, I will explain the Ordering class which combines the power of Comparators with Collections' functionality and which adds other interesting features (such as compound comparators). This class is really useful if you need to order your Iterable, find the maximum/minimum element in your Iterable, find the index of an arbitrary element. It implements Comparator interface for backward compatibility.
I will use a basic Employee class during my examples. Employee is a mutable class with three attributes: id, name and years of service..
As I implemented Comparable in the Employee class, I have to add compareTo(). In this method I only compare the name of the employees. I'll create three employees and add them to an ArrayList.
There are many ways to create an Ordering. You can create one using the good old Comparator, using a predefined list of objects that explicitly imposes the ordering strategy, using the toString() method of the objects in hand and using the compareTo() method of the objects. You'll need to implement Comparable in your object if you want to take the compareTo() road. Lets create two comparators. One for comparing the years of service and another for employee id.
The example above is not different from calling Collections.sort() with the comparator in hand but notice that we don't sort Collections but Iterables.
With explicit(), we create an Ordering where we impose an order explicitly.
I want to order en enum type (colors) and I want red, blue, green as order. I created the enum type as instance variable.
Not lets see the Ordering part.
Notice that explicit() works only with the given objects. You can't sort you iterable if you didnt specify the order in explicit(). If you try to to that you'll get IncomparableValueException.
Let me show you how to create an Ordering using toString() method of the object in hand.
Lets create an Ordering with natural ordering (using compareTo() of the objects)
We can do binary search on the sorted list for an element. Notice that the Ordering that calls the binary search method and Ordering that sorted the Iterable in hand must be the same. binarySearch() was available in Collections class just like min() and max() we'll see in next examples.
I will add elements of employee list, 2 null elements to a new list so we can explore new methods related to the handling of null elements.
2 methods can be used for changing the handling of null elements. nullsFirst(), (nullsLast()) returns an Ordering which puts null elements to the beginning (end) of every non-null value.
I'd like to find the employee with the highest (lowest) time of service. I can do a sort based on years of service but that'll be slower then doing a single sweep for finding the element with max (min) year of service.
In each ordering we defined an increasing order. We can reverse the Ordering calling reverse() and obtaining a new Ordering. Lets build a new ordering that'll use the idComparator.
A useful ability of Orderings is the fact that you can combine multiple Comparators with it. Call compound() for this. If the result of comparator1 is 0 then the second one will be called and this will continue until a non-zero value (a larger/smaller relationship) is obtained from the comparator. If all comparators return 0 then the elements are treated as equal (we get 0 from the combined comparator).
As you can see the years of service increase (3 then 5 then two 8). When years of service comparator see that the result is a draw the second comparator is called. As you can see Mr Pink and Mr Brown have the same years of service so their id are inspected and the order between them is calculated. As the id of Mr Pink is less than Mr Brown's he's before Mr Brown.
This is all for compound comparators.
There are two slightly different methods for checking if the iterable in hand is ordered. isOrdered() checks if each element is less than/equal to the subsequent element. isStrictlyOrdered() checks if each element is strictly less than the subsequent element.
Using functions as Ordering is quite interesting, but I will explain functional programming capabilities later so lets skip it for the moment.
I will use a basic Employee class during my examples. Employee is a mutable class with three attributes: id, name and years of service..
class Employee implements Comparable < Employee > {
private int id;
private String name;
private int yearsOfService;
public Employee(int id, String name, int yearsOfService){
this.id = id;
this.name = name;
this.yearsOfService = yearsOfService;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getYearsOfService() {
return yearsOfService;
}
public void setYearsOfService(int yearsOfService) {
this.yearsOfService = yearsOfService;
}
@Override
public int compareTo(Employee employee) {
return this.getName().compareTo(employee.getName());
}
@Override
public String toString() {
String toString = "id="+id
+"-name="+name+"-years of service="+yearsOfService;
return toString;
}
}
As I implemented Comparable in the Employee class, I have to add compareTo(). In this method I only compare the name of the employees. I'll create three employees and add them to an ArrayList.
Employee sezinKarli = new Employee(4, "Sezin Karli", 4);
Employee darthVader = new Employee(3, "Darth Vader", 5);
Employee hanSolo = new Employee(2, "Han Solo", 10);
List < Employee > employeeList =
Lists.newArrayList(sezinKarli, hanSolo, darthVader);
System.out.println("employee list: "+employeeList);
//output:
//employee list: [id=4-name=Sezin Karli-years of service=4,
// id=2-name=Han Solo-years of service=10,
// id=3-name=Darth Vader-years of service=5]
There are many ways to create an Ordering. You can create one using the good old Comparator, using a predefined list of objects that explicitly imposes the ordering strategy, using the toString() method of the objects in hand and using the compareTo() method of the objects. You'll need to implement Comparable in your object if you want to take the compareTo() road. Lets create two comparators. One for comparing the years of service and another for employee id.
Comparator < Employee > yearsComparator =
new Comparator < Employee >(){
@Override
public int compare(Employee employee1, Employee employee2) {
return (
employee1.getYearsOfService() - employee2.getYearsOfService());
}
};
Comparator < Employee > idComparator =
new Comparator < Employee >(){
@Override
public int compare(Employee employee1, Employee employee2) {
return (employee1.getId() - employee2.getId());
}
};
//Create an Ordering from a Comparator
Ordering < Employee > orderUsingYearsComparator =
Ordering.from(yearsComparator);
//Sort the employee list using years comparator
List < Employee > sortedCopy =
orderUsingYearsComparator.sortedCopy(employeeList);
System.out.println(
"sorted copy based on years of service comparator: "+sortedCopy);
/*
output:
sorted copy based on years of service comparator:
[id=4-name=Sezin Karli-years of service=4,
id=3-name=Darth Vader-years of service=5,
id=2-name=Han Solo-years of service=10]
*/
The example above is not different from calling Collections.sort() with the comparator in hand but notice that we don't sort Collections but Iterables.
With explicit(), we create an Ordering where we impose an order explicitly.
I want to order en enum type (colors) and I want red, blue, green as order. I created the enum type as instance variable.
static enum Colors{RED, GREEN, BLUE, YELLOW};
Not lets see the Ordering part.
Ordering < Colors > explicitOrdering =
Ordering.explicit(Colors.RED, Colors.BLUE, Colors.GREEN);
List < Colors > colorList =
Lists.newArrayList(Colors.BLUE, Colors.RED,
Colors.BLUE, Colors.GREEN, Colors.RED);
List < Colors > sortedCopy8 =
explicitOrdering.sortedCopy(colorList);
System.out.println("ordered color list: "+sortedCopy8);
//ordered color list: [RED, RED, BLUE, BLUE, GREEN]
//we imposed the RED, BLUE, GREEN order and
//the result conforms to that
Notice that explicit() works only with the given objects. You can't sort you iterable if you didnt specify the order in explicit(). If you try to to that you'll get IncomparableValueException.
Let me show you how to create an Ordering using toString() method of the object in hand.
Ordering < Object > usingToString = Ordering.usingToString();
// returns an ordering which uses the natural
// order comparator on toString() results of objects
List < Employee > sortedCopy3 =
usingToString.sortedCopy(employeeList);
System.out.println("sorted usingToString: "+sortedCopy3);
/*
sorted usingToString:
[id=2-name=Han Solo-years of service=10,
id=3-name=Darth Vader-years of service=5,
id=4-name=Sezin Karli-years of service=4]
*/
Lets create an Ordering with natural ordering (using compareTo() of the objects)
Ordering < Employee > natural = Ordering.natural();
List < Employee > sortedCopy4 = natural.sortedCopy(employeeList);
System.out.println("sorted with natural: "+sortedCopy4);
/*
sorted with natural:
[id=3-name=Darth Vader-years of service=5,
id=2-name=Han Solo-years of service=10,
id=4-name=Sezin Karli-years of service=4]
*/
We can do binary search on the sorted list for an element. Notice that the Ordering that calls the binary search method and Ordering that sorted the Iterable in hand must be the same. binarySearch() was available in Collections class just like min() and max() we'll see in next examples.
int binarySearch = natural.binarySearch(sortedCopy4, sezinKarli);
System.out.println("My index in the list: "+binarySearch); // 2
I will add elements of employee list, 2 null elements to a new list so we can explore new methods related to the handling of null elements.
List < Employee > employeeListWithNulls =
new ArrayList < Employee > (employeeList);
employeeListWithNulls.add(null);
employeeListWithNulls.add(null);
2 methods can be used for changing the handling of null elements. nullsFirst(), (nullsLast()) returns an Ordering which puts null elements to the beginning (end) of every non-null value.
// sort the employee list with natural ordering
// and put the null elements to the beginning
List < Employee > sortedCopy5 =
natural.nullsFirst().sortedCopy(employeeListWithNulls);
System.out.println("nulls first: "+sortedCopy5);
/*
nulls first:
[null, null, id=3-name=Darth Vader-years of service=5,
id=2-name=Han Solo-years of service=10,
id=4-name=Sezin Karli-years of service=4]
*/
// sort the employee list with natural ordering
//and put the null elements to the ending
List < Employee > sortedCopy6 =
natural.nullsLast().sortedCopy(employeeListWithNulls);
System.out.println("nulls last: "+sortedCopy6);
/*
nulls last:
[id=3-name=Darth Vader-years of service=5,
id=2-name=Han Solo-years of service=10,
id=4-name=Sezin Karli-years of service=4, null, null]
*/
I'd like to find the employee with the highest (lowest) time of service. I can do a sort based on years of service but that'll be slower then doing a single sweep for finding the element with max (min) year of service.
Employee employeeWithMaxYearsOfService =
orderUsingYearsComparator.max(employeeList);
System.out.println(employeeWithMaxYearsOfService);
// Han solo has the biggest year of service for the company
//lets find the minimum
Employee employeeWithMinYearsOfService =
orderUsingYearsComparator.min(employeeList);
System.out.println(employeeWithMinYearsOfService);
// Sezin has the smallest year of service for the company
/*
* min() and max() can be used for any iterable.
* Notice that these methods are overloaded and
* it's possible to use them on two elements or
* an arbitrary number of elements (var-arg)
* */
//Sezin or Darth has the longest year of service?
Employee max =
orderUsingYearsComparator.max(sezinKarli, darthVader);
System.out.println(max); //Vader
//Lets see the var-arg version,
// The result below must be the same
//with employeeWithMaxYearsOfService
//because we used each element in the
// employee list and the same Ordering
Employee max2 =
orderUsingYearsComparator.max(sezinKarli, darthVader, hanSolo);
System.out.println(
"Are the max results the same?: "
+max2.equals(employeeWithMaxYearsOfService)); //true
In each ordering we defined an increasing order. We can reverse the Ordering calling reverse() and obtaining a new Ordering. Lets build a new ordering that'll use the idComparator.
Ordering < Employee > reverseIdOrdering =
Ordering.from(idComparator).reverse();
// We will have an ordering of decreasing employee ids if we use
// this Ordering
List < Employee > employeeWithReverseIdOrder =
reverseIdOrdering.sortedCopy(employeeList);
System.out.println(
"employeeWithReverseIdOrder:"+ employeeWithReverseIdOrder);
/*
employeeWithReverseIdOrder:[
id=4-name=Sezin Karli-years of service=4,
id=3-name=Darth Vader-years of service=5,
id=2-name=Han Solo-years of service=10]
*/
// As you can see the ids are 4, 3 and
//2 (an array with decreasing order
A useful ability of Orderings is the fact that you can combine multiple Comparators with it. Call compound() for this. If the result of comparator1 is 0 then the second one will be called and this will continue until a non-zero value (a larger/smaller relationship) is obtained from the comparator. If all comparators return 0 then the elements are treated as equal (we get 0 from the combined comparator).
List < Employee > newEmployeeList =
Lists.newArrayList(new Employee(1, "Mr Pink", 8),
new Employee(2, "Mr Brown", 8), new Employee(3, "Mr Green", 3),
new Employee(4, "Mr Yellow", 5));
//We previously created an Ordering
// by id (orderUsingYearsComparator)
//Now lets add id comparator to this Ordering
Ordering < Employee > combinedComparatorOrdering =
orderUsingYearsComparator.compound(idComparator);
List < Employee > sortedCopy7 =
combinedComparatorOrdering.sortedCopy(newEmployeeList);
//First by years of service then by id
System.out.println("Combined comparators: "+sortedCopy7);
/*Combined comparators:
[id=3-name=Mr Green-years of service=3,
id=4-name=Mr Yellow-years of service=5,
id=1-name=Mr Pink-years of service=8,
id=2-name=Mr Brown-years of service=8]
*/
As you can see the years of service increase (3 then 5 then two 8). When years of service comparator see that the result is a draw the second comparator is called. As you can see Mr Pink and Mr Brown have the same years of service so their id are inspected and the order between them is calculated. As the id of Mr Pink is less than Mr Brown's he's before Mr Brown.
This is all for compound comparators.
There are two slightly different methods for checking if the iterable in hand is ordered. isOrdered() checks if each element is less than/equal to the subsequent element. isStrictlyOrdered() checks if each element is strictly less than the subsequent element.
List < Integer > integers = Lists.newArrayList(1, 2, 3, 4);
// This should return true from isOrdered() and isStrictlyOrdered()
// because the numbers are increasing( isOrdered() = true)
// and there's no consecutive and equal
// elements (isStrictlyOrdered = true)
boolean ordered = Ordering.natural().isOrdered(integers);
System.out.println("isOrdered: "+ordered);
boolean strictlyOrdered =
Ordering.natural().isStrictlyOrdered(integers);
System.out.println("isStrictlyOrdered: "+strictlyOrdered);
//Lets use another list with equal elements inside
List < Integer > newIntegers =
Lists.newArrayList(1, 2, 3, 3, 4);
// The numbers are increasing( isOrdered() = true)
// and there's consecutive and equal
// elements (isStrictlyOrdered = false)
ordered = Ordering.natural().isOrdered(newIntegers);
System.out.println("isOrdered: "+ordered);
strictlyOrdered =
Ordering.natural().isStrictlyOrdered(newIntegers);
System.out.println("isStrictlyOrdered: "+strictlyOrdered);
Using functions as Ordering is quite interesting, but I will explain functional programming capabilities later so lets skip it for the moment.
at
15:27
Labels:
binary search,
collections,
comparable,
comparator,
google,
guava,
iterables,
java,
java library,
max,
min,
natural ordering,
order,
ordering,
programming,
sort,
sorting,
tutorial
Tuesday, May 11, 2010
google's guava library tutorial part 1: fun with string-related stuff
I was planning to create a Guava tutorial. But it seems like it'll be too large for a single post, so I opted on splitting it into several parts. The first part contains everything related to Strings. Four main classes are explained:
CharMatcher can be thought as a Pattern+Matcher of JDK in a more simple and practical form. It's not a full fledged replacement because you can't use regular expressions as you do on JDK.
You can negate the matcher so it accepts the complementary character set. e.g. if our CharMatcher was accepting {a, b, c}, it'll accept any character except {a, b, c}.
removeFrom() and retainFrom() are really convenient methods. The first one removes the matching string while the second one extracts the matching string.
indexIn() returns the index of the first matching character.
Although it's possible to use CharMatcher with predefined matcher setting you can as well build your own.
You can use trimFrom(), trimLeadingFrom() and trimTrailingFrom() for enhanced trimming capability. Next class is the Joiner class. You probably know splitting capabilities of JDK. It's a mystery why a string joining mechanism is not added to JDK. Guava's Joiner is here to help you in case you need one. Joiner basically takes an iterable or an array and joins all the elements inside as Strings. After that, you can directly add it to a StringBuilder, an Appendable (like PrintWriter, BufferedWriter ... etc), or obtain a String in the "element1 SEPARATOR element2...." form. We choose the separator with on() method of Joiner class. It's possible to use a CharMatcher, a Pattern or a String as separator.
If you have predefined String values no need to create an array or an iterable for joining them. Notice that you can join an arbitrary number of objects with the method below. The method works with var-args.
Notice that if neither skipNulls() nor useForNull(String)is used, the joining methods will throw NullPointerException if any given element is null.
Joiner is for iterables and arrays. Joiner.MapJoiner inner class is the map counterpart of Joiner. You can join the map content directly using Joiner.MapJoiner class. First you have to build a Joiner and assign it a separator(1) using on(). Then you can call withKeyValueSeparator() which takes the separator(2) between key value pairs This map joiner can be used to join a map for obtaining a string or this can be appended to an Appendable. The form of the result is "key1 SEPARATOR(1) value1 SEPARATOR(2) key2 SEPARATOR(1) value2 SEPARATOR(2)..." without the empty spaces.
Google Guava library contains a cool Splitter class that harness more power than the JDK's split functionality.
I'd want to remove the empty elements and then trim each element to remove the unnecessary empty spaces before and after them. I can do this in several steps with the old splitter. It's quite easy with Guava's Splitter.
Notice that trimming is applied before checking for an empty result, regardless of the order in which the trimResults() and omitEmptyStrings() methods were invoked.
Strings class contains a number of utility methods.Most of them are checking String objects'. emptyToNull() and nullToEmpty() are quite similar. emptyToNull (nullToEmpty) returns the given string if it is non-empty (non-null) else it returns an empty (null) string.
isNullOrEmpty() is quite practical. I don't remember how many times I had to write (string != null && !string.isEmpty())in my code.
I'll show you repeat() which returns a string consisting of the given number of concatenated copies of the input string.
padEnd() and padStart() are quite similar. The first one adds the given char at the end of the given string as many times as the given integer value allows. The second one adds to the start.
This is all for string-related classes of Guava.
- CharMatcher (which can be considered as a light form of JDK's Pattern+Matcher with string manipulation capabilities)
- Joiner and MapJoiner (which are useful for joining iterables or arrays into string representations)
- Splitter (which is split() of JDK on steroids).
CharMatcher can be thought as a Pattern+Matcher of JDK in a more simple and practical form. It's not a full fledged replacement because you can't use regular expressions as you do on JDK.
String string = "Scream 4";
// I get a predefined CharMatcher
//which will accept letters or digits
CharMatcher matcher = CharMatcher.JAVA_LETTER_OR_DIGIT;
// You can find how many times a letter
// or a digit is seen
// Much more practical to use a Pattern
//and a Matcher then iterate over the
//Matcher results for counting
int count = matcher.countIn(string);
System.out.println("Letter or digit count: "+count);
// 7 characters
/*
* matchesAllOf (matchesNoneOf) checks
* if all (none) of the elements
* in the given string matches with the
* matcher in hand.
* */
System.out.println(matcher.matchesAllOf("scream"));
// true
System.out.println(matcher.matchesAllOf("scream "));
// false because there's an empty
//space at the end
System.out.println(matcher.matchesNoneOf("_?=)("));
// true because no letters or
//digits in it
You can negate the matcher so it accepts the complementary character set. e.g. if our CharMatcher was accepting {a, b, c}, it'll accept any character except {a, b, c}.
CharMatcher negatedMatcher = matcher.negate();
/*
* You can think that true, false,
* true will become false, true, false
* because now our matcher is a
* non-letter, non-digit matcher.
* But no, the result will be false,
* false, false.
* The interesting one is the second one.
* The negatedMatcher matches only
* the empty space part of "scream ".
* So it returns "false".
* */
System.out.println(negatedMatcher.matchesAllOf("scream"));
//false
System.out.println(negatedMatcher.matchesAllOf("scream "));
//false
System.out.println(negatedMatcher.matchesNoneOf("_?=)("));
//false
removeFrom() and retainFrom() are really convenient methods. The first one removes the matching string while the second one extracts the matching string.
String review = "Scream 4 is the #1 teen-slasher!";
CharMatcher whitespaceMatcher = CharMatcher.JAVA_WHITESPACE;
String result = whitespaceMatcher.removeFrom(review);
// This matcher will remove the
//matching characters (whitespaces)
System.out.println("The sentence without whitespaces: "+result);
//output: Scream4isthe#1teen-slasher!
/*
* I want the numbers in the text above.
* I can do that by first taking
*the predefined digit CharMatcher and
* then calling retainFrom() for
* the string in hand.
* */
String result2 = CharMatcher.DIGIT.retainFrom(review);
System.out.println("Retained digits: "+result2);
// I'll get '41' as a result
// because I have 4 and 1 as digits
indexIn() returns the index of the first matching character.
//I'd like to learn the index
// of the digit result too.
//The first element is '4'
int indexOfDigit = CharMatcher.DIGIT.indexIn(review);
System.out.println("index Of Digit: "+indexOfDigit);
// 4's index is 7
Although it's possible to use CharMatcher with predefined matcher setting you can as well build your own.
CharMatcher onlyEvenNumbersMatcher = CharMatcher.anyOf("2468");
// This accepts any even number
CharMatcher noEvenNumbersMatcher = CharMatcher.noneOf("2468");
// This accepts everything
//but even numbers
CharMatcher largeAtoZ = CharMatcher.inRange('A', 'Z');
CharMatcher aToZ = CharMatcher.inRange('a', 'z').or(largeAtoZ);
// we added A-Z with 'or' here.
// You can join CharMatchers
// with "and" too.
System.out.println(
"Even numbers matcher result: "
+onlyEvenNumbersMatcher.matchesAllOf("1354"));
// false. 1,3,5 are not ok
System.out.println(
"Even numbers matcher result: "
+onlyEvenNumbersMatcher.matchesAllOf("starwars"));
// false. only even numbers are ok
System.out.println(
"Even numbers matcher result: "
+onlyEvenNumbersMatcher.matchesAllOf("2466"));
// true. all of them are even
System.out.println(
"No even numbers matcher result: "
+noEvenNumbersMatcher.matchesAllOf("1354"));
// false. 4 is not ok
System.out.println(
"No even numbers matcher result: "
+noEvenNumbersMatcher.matchesAllOf("1337"));
// true. none of them are even
System.out.println(
"No even numbers matcher result: "
+noEvenNumbersMatcher.matchesAllOf("supermario"));
// true. none of them are even
System.out.println(
"a to Z matcher result: "+aToZ.matchesAllOf("sezin"));
System.out.println(
"a to Z matcher result: "+aToZ.matchesAllOf("Sezin"));
System.out.println(
"a to Z matcher result: "+aToZ.matchesAllOf("SeZiN"));
System.out.println(
"a to Z matcher result: "+aToZ.matchesAllOf("SEZIN"));
// true. all strings are ok.
// All of the characters are
// in {a, .., z} and {A, .., Z} range
System.out.println(
"a to Z matcher result: "+aToZ.matchesAllOf("scream4"));
// false. if 4 was not here every
// character in hand was in [a-Z]
You can use trimFrom(), trimLeadingFrom() and trimTrailingFrom() for enhanced trimming capability. Next class is the Joiner class. You probably know splitting capabilities of JDK. It's a mystery why a string joining mechanism is not added to JDK. Guava's Joiner is here to help you in case you need one. Joiner basically takes an iterable or an array and joins all the elements inside as Strings. After that, you can directly add it to a StringBuilder, an Appendable (like PrintWriter, BufferedWriter ... etc), or obtain a String in the "element1 SEPARATOR element2...." form. We choose the separator with on() method of Joiner class. It's possible to use a CharMatcher, a Pattern or a String as separator.
// lets build an array list with //4 letters content ArrayListcharList = Lists.newArrayList("a", "b", "c", "d"); StringBuilder buffer = new StringBuilder(); // You can easily add the joined // element list to a StringBuilder buffer = Joiner.on("|").appendTo(buffer, charList); System.out.println( "Joined char list appended to buffer: "+buffer.toString()); // Joined char list appended to buffer: a|b|c|d //Below we join a list with ", " // separator for obtaining a String String joinedCharList = Joiner.on(", ").join(charList); System.out.println( "Joined char list as String: "+joinedCharList); //Joined char list as String: a, b, c, d //I'm adding a null value for // further exploration of Joiner features charList.add(null); System.out.println(charList); // null at the end: //[a, b, c, d, null] // Below the Joiner will skip // null valued elements automatically String join4 = Joiner.on(" - ").skipNulls().join(charList); System.out.println(join4); // output: a - b - c - d // Below, the Joiner will give // a value to null valued elements automatically join4 = Joiner.on(" - "). useForNull("defaultValue").join(charList); System.out.println(join4); // output: a - b - c - d - defaultValue
If you have predefined String values no need to create an array or an iterable for joining them. Notice that you can join an arbitrary number of objects with the method below. The method works with var-args.
join4 = Joiner.on("|").
join("first", "second", "third", "fourth", "rest");
System.out.println(join4);
//output: first|second|third|fourth|rest
Notice that if neither skipNulls() nor useForNull(String)is used, the joining methods will throw NullPointerException if any given element is null.
Joiner is for iterables and arrays. Joiner.MapJoiner inner class is the map counterpart of Joiner. You can join the map content directly using Joiner.MapJoiner class. First you have to build a Joiner and assign it a separator(1) using on(). Then you can call withKeyValueSeparator() which takes the separator(2) between key value pairs This map joiner can be used to join a map for obtaining a string or this can be appended to an Appendable. The form of the result is "key1 SEPARATOR(1) value1 SEPARATOR(2) key2 SEPARATOR(1) value2 SEPARATOR(2)..." without the empty spaces.
Map < String, Long > employeeToNumber = Maps.newHashMap();
// Create a Map using static
// method of Maps
employeeToNumber.put("obi wan", 1L);
employeeToNumber.put("bobba", 2L);
MapJoiner mapJoiner =
Joiner.on("|").withKeyValueSeparator("->");
// | between each key-value pair
//and -> between a key and its value
String join5 = mapJoiner.join(employeeToNumber);
System.out.println(join5);
//output is "obi wan->1|bobba->2".
Google Guava library contains a cool Splitter class that harness more power than the JDK's split functionality.
String text = "I have to test my string splitter,
for this purpose I'm writing this text, ";
//I want to split the text
// above using ","
// I'll have three elements
// with the usual splitter:
// first sentence, then the
//second sentence and the empty space at the end.
String[] split = text.split(","); // split with ","
System.out.println(Arrays.asList(split));
//output: [I have to test my string splitter,
//for this purpose I'm writing this text, ]
I'd want to remove the empty elements and then trim each element to remove the unnecessary empty spaces before and after them. I can do this in several steps with the old splitter. It's quite easy with Guava's Splitter.
// Again, the on parameter is the separator. //You can use a CharMatcher, //a Pattern or a String as a separator. Iterablesplit2 = Splitter.on(",").omitEmptyStrings() .trimResults().split(text); System.out.println(Lists.newArrayList(split2)); // output: //[I have to test my string splitter, // for this purpose I'm writing this text] // I can split tokens of length 5 //from the string in hand Iterable split3 = Splitter.fixedLength(5).split(text); System.out.println(Lists.newArrayList(split3)); // each token's length is 5 //output: //[I hav, e to , test , my st, ring , split, // ter, , for , this , purpo, se I', m wri, // ting , this , text,, ]
Notice that trimming is applied before checking for an empty result, regardless of the order in which the trimResults() and omitEmptyStrings() methods were invoked.
Strings class contains a number of utility methods.Most of them are checking String objects'. emptyToNull() and nullToEmpty() are quite similar. emptyToNull (nullToEmpty) returns the given string if it is non-empty (non-null) else it returns an empty (null) string.
String emptyToNull = Strings.emptyToNull("test");
System.out.println(emptyToNull);
// returns "test" because it's not empty
emptyToNull = Strings.emptyToNull("");
System.out.println(emptyToNull);
// returns null because the argument is empty
isNullOrEmpty() is quite practical. I don't remember how many times I had to write (string != null && !string.isEmpty())in my code.
String arg = "";
boolean nullOrEmpty = Strings.isNullOrEmpty(arg);
// arg is empty
System.out.println("Null or Empty?: "+nullOrEmpty);
// true because it's empty
arg = null;
nullOrEmpty = Strings.isNullOrEmpty(arg); // arg is null
System.out.println("Null or Empty?: "+nullOrEmpty);
// true because it's null
arg = "something";
nullOrEmpty = Strings.isNullOrEmpty(arg);
// arg is not null or empty so the result is 'false'
System.out.println("Null or Empty?: "+nullOrEmpty);
I'll show you repeat() which returns a string consisting of the given number of concatenated copies of the input string.
String repeat = Strings.repeat("beetlejuice", 3);
System.out.println(repeat);
// output is "beetlejuicebeetlejuicebeetlejuice"
padEnd() and padStart() are quite similar. The first one adds the given char at the end of the given string as many times as the given integer value allows. The second one adds to the start.
String padEnd = Strings.padEnd("star wars", 15, 'X');
String padStart = Strings.padStart("star wars", 15, 'X');
System.out.println("padEnd: "+padEnd);
// padEnd: star warsXXXXXX
System.out.println("padStart: "+padStart);
// padStart: XXXXXXstar wars
System.out.println(padStart.length() == 15);
// true, because we give 15 as character limit
This is all for string-related classes of Guava.
at
13:27
Labels:
charmatcher,
google,
guava,
java,
java 5,
java library,
jdk,
joiner,
mapjoiner,
matcher,
pattern,
programming,
regex,
regular expressions,
splitter,
string,
string manipulation,
strings,
tutorial
Friday, September 18, 2009
google collections api
Every developer that works with Java collections for some time will realize the limitations of Java's Collections API. It looks like Google developers share the same opinion which results in the development of their own API. Benjamin Winterberg has a good blog entry about the said API.
Saturday, March 21, 2009
you wish you could catch and cancel that email you sent, don't you?
If your answer to the title of this entry is yes or YES or several time yes/YES, then rejoice because now gmail can undo emails. After you send an email with google mail, you have five seconds to change your opinion and cancel sending this mail. It is an inarguably useful feature considering how many times you (I) wish you (I) didn't send "that" email. A job application without a CV attached to it is not that effective isn't it? Yeah I though so...
Notice that it's a labs feature. You have to activate it from there to use it.
Notice that it's a labs feature. You have to activate it from there to use it.
Friday, February 13, 2009
igoogle's language switching proglem
I'm using iGoogle because I like the idea of having a personalized homepage with my e-mails, todo list, current weather information and aggregated news from different sources in it. But although I'm using a Windows Vista in English, iGoogle keeps on turning the language to Turkish (probably due to the regional settings of my Windows) and lots of its content are changing (which annoys me very much). So I'll present you the tip to change the language of your iGoogle into English: add "?hl=en" to http://www.google.com/ig and use http://www.google.com/ig?hl=en.
Friday, January 16, 2009
read attached pdf without acrobat reader
Thanks to Gmail's new service, it is possible to read PDF files attached to e-mails without the need of saving them and opening them with Acrobat Reader. I tried the new feature and it worked flawless as long as I could test it. As you can see in the picture, all you have to do is to click on "view" to read the PDF file.
Tuesday, December 2, 2008
gaudi: google audio indexing and in quotes
Google's audio indexing service basically scans video content (from Youtube) for extracting audio data from it. Later, it applies a speech recognition algorithm for extracting words from obtained audio data and then index this textual data; GAUDI is not as interesting as it should be due to the spesific catalogue that it works on. For now, it's limited to election material of US presidency.
Another addition to Google Labs is "In Quotes" which's an application less ambitious than GAUDI. In Quotes can search words from newspapers and magazines and it is -again- limited to election material. Interested to find Sarah Palin's words on Turkey. Then visit In Quotes.
Subscribe to:
Posts (Atom)