1. Table
2. ImmutableCollections
3. Comparision Chain & Range
4. Ordering
1. Table: Map<R, Map<C, V>>
1> Create table
package edu.xmu.guava.collection;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import com.google.common.collect.HashBasedTable;
public class TableTest {
@Test
public void createTest() {
HashBasedTable<Integer, Integer, String> table = HashBasedTable
.create();
table.put(0, 0, "A");
table.put(0, 1, "B");
table.put(0, 2, "C");
table.put(1, 0, "D");
table.put(1, 1, "E");
assertTrue(table.contains(0, 0));
assertTrue(table.contains(1, 1));
assertFalse(table.contains(1, 2));
assertFalse(table.contains(2, 0));
table = HashBasedTable.create(2, 2);
table.put(0, 0, "A");
table.put(0, 1, "B");
table.put(0, 2, "C"); // Will auto expand to ensure capacity
table.put(1, 0, "D");
table.put(1, 1, "E");
HashBasedTable<Integer, Integer, String> table2 = HashBasedTable
.create(table);
assertEquals(2, table2.rowMap().size()); // total 2 rows
assertEquals(3, table2.row(0).size()); // total 3 cols in row 0
assertEquals(3, table2.columnMap().size()); // total 3 cols
assertEquals(1, table2.column(2).size()); // total 1 row in col 2
table2.remove(0, 2);
assertEquals(2, table2.rowMap().size()); // total 2 rows
assertEquals(2, table2.row(0).size()); // total 3 cols in row 0
assertEquals(2, table2.columnMap().size()); // total 2 cols
assertEquals(2, table2.column(1).size()); // total 2 rows in col 1
}
}
This is the graph representation of the table created above.
2> Table Views: The table provides some great methods for obtaining different views of the underlying data in the table.Map<Integer, String> columnMap = table.column(columnNo);
Map<Integer, String> rowMap = table.row(rowNo);
package edu.xmu.guava.collection;
import static org.junit.Assert.assertEquals;
import java.util.Map;
import org.junit.Test;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Table;
public class TableTest {
@Test(expected = UnsupportedOperationException.class)
public void tableViewTest() {
Table<Integer, Integer, String> table = HashBasedTable.create();
table.put(0, 0, "A");
table.put(0, 1, "B");
table.put(0, 2, "C");
table.put(1, 0, "D");
table.put(1, 1, "E");
assertEquals("C", table.row(0).get(2));
assertEquals("D", table.row(1).get(0));
assertEquals("E", table.row(1).get(1));
Map<Integer, String> rowMap = table.row(0);
rowMap.put(3, "F"); // table is updated
assertEquals("F", table.row(0).get(3));
Map<Integer, String> colMap = table.column(2);
colMap.put(3, "G"); // table is updated
assertEquals("G", table.row(3).get(2));
assertEquals("G", table.column(2).get(3));
Table<Integer, Integer, String> immutableTable = ImmutableTable
.<Integer, Integer, String> builder().putAll(table).build();
rowMap = immutableTable.row(0);
rowMap.put(4, "H"); // UnsupporttedOperationException will be thrown
}
}
2. ImmutableCollections
1) If we don't explicitly have a need for a mutable collection, we should always favor using an immutable one.
First of all, immutable collections are completely thread-safe.
Secondly, they offer protection from unknown users who may try to access your code.
@Test
public void test() {
List<String> list = Lists.newArrayList("A", "B", "C", "D", "E");
List<String> addedList = ImmutableList.<String> builder().addAll(list)
.add("F").build();
assertEquals(Lists.newArrayList("A", "B", "C", "D", "E", "F"),
addedList);
addedList = new ImmutableList.Builder<String>().addAll(list).add("G")
.build();
assertEquals(Lists.newArrayList("A", "B", "C", "D", "E", "G"),
addedList);
}
We can see in source code that ImmutableXXX.<T>builder() == new ImmutableXXX.Builder<T>();
public static <E> Builder<E> builder() {
return new Builder<E>();
}
Builder pattern is used to create an ImmutableXXX instance.
3. ComparisonChain & Range
1) ComparisionChain:
1> UML for ComparisionChain: Attention that they are using Chain of Responsibity design pattern here.
2> Usage:
package edu.xmu.guava.collection;
import java.util.Set;
import org.apache.log4j.Logger;
import org.junit.Test;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
public class ComparisionChainTest {
Logger logger = Logger.getLogger(ComparisionChainTest.class);
@Test
public void sortTest() {
Set<Person> persons = Sets.newTreeSet(Lists.newArrayList(new Person(
"Yang", 23), new Person("Yang", 20), new Person("Yang", 33),
new Person("Li", 12), new Person("Zhang", 21)));
logger.info(persons);
}
static class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public int compareTo(Person o) {
return ComparisonChain.start().compare(this.name, o.name)
.compare(this.age, o.age).result();
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
}
2) Range:
1> It is usually used with ComparisionChain and serve as/for Predicate
2> Range object implements the Predicate interface
@Test
public void comparableTest() {
Range<Person> personRange = Range.closed(new Person("A", 1),
new Person("B", 21));
assertTrue(personRange.contains(new Person("A", 2)));
assertTrue(personRange.contains(new Person("A", 21)));
assertTrue(personRange.contains(new Person("A", Integer.MAX_VALUE)));
assertTrue(personRange.contains(new Person("B", 1)));
assertTrue(personRange.contains(new Person("B", 21)));
assertFalse(personRange.contains(new Person("B", 22)));
}
public static class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Person o) {
return ComparisonChain.start().compare(this.name, o.name)
.compare(this.age, o.age).result();
}
}
@Test
public void comparableTest2() {
Range<Person> personRange1 = Range.closed(new Person("A", 1),
new Person("C", 1));
Range<Person> personRange2 = Range.closed(new Person("D", 1),
new Person("F", 2));
Predicate<Person> personPredicate = Predicates.or(personRange1,
personRange2);
assertTrue(personPredicate.apply(new Person("B", 1)));
assertTrue(personPredicate.apply(new Person("C", 1)));
assertTrue(personPredicate.apply(new Person("D", Integer.MAX_VALUE)));
assertTrue(personPredicate.apply(new Person("E", 1)));
assertTrue(personPredicate.apply(new Person("E", Integer.MAX_VALUE)));
assertFalse(personPredicate.apply(new Person("F", 3)));
}
4. Ordering:
package edu.xmu.guava.collections;
import static org.junit.Assert.assertEquals;
import java.util.Comparator;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
public class OrderingTest {
List<String> versionList;
List<String> descSortedVersionList;
@Before
public void setUp() {
versionList = Lists.newArrayList("11-0", "1-1", "2-1", "11-21",
"11-111", "0-1");
descSortedVersionList = Lists.newArrayList("11-111", "11-21", "11-0",
"2-1", "1-1", "0-1");
}
@Test
public void sortTest() {
List<String> sortedVersionList = Ordering
.from(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
Function<String, Integer> parseIntFunc = new Function<String, Integer>() {
@Override
public Integer apply(String input) {
return Integer.parseInt(input);
}
};
List<Integer> prevVersions = FluentIterable
.from(Splitter.on('-').trimResults()
.omitEmptyStrings().split(o1))
.transform(parseIntFunc).toList();
List<Integer> currVersions = FluentIterable
.from(Splitter.on('-').trimResults()
.omitEmptyStrings().split(o2))
.transform(parseIntFunc).toList();
return ComparisonChain
.start()
.compare(prevVersions.get(0),
currVersions.get(0))
.compare(prevVersions.get(1),
currVersions.get(1)).result();
}
}).reverse().sortedCopy(versionList);
assertEquals(descSortedVersionList, sortedVersionList);
}
@Test
public void sortTest2() {
List<Person> personList = Lists.newArrayList(new Person("Yang", "Male",
1), new Person("Li", "Female", 2), new Person("Zhang", "Male",
24), new Person("Yang", "Female", 20));
List<Person> sortedPersonList = Ordering.from(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.name.compareTo(o2.name);
}
}).compound(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.age - o2.age;
}
}).compound(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.gender.compareTo(o2.gender);
}
}).sortedCopy(personList);
System.out.println(sortedPersonList);
}
public class Person {
private String name;
private String gender;
private int age;
public Person(String name, String gender, int age) {
super();
this.name = name;
this.gender = gender;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", gender=" + gender + ", age="
+ age + "]";
}
}
}
Comments: We can use Ordering without changing the Person (no need to implements Comparable).
Reference Links:
1) Getting Started with Google Guava -Bill Bejeck