Guava-Working with Collections

The FluentIterable class

  • FluentIterable.from(final Iterable iterable)
  • FluentIterable.filter(Predicate<? super E> predicate)
  • FluentIterable.transform(Function<? super E, T> function)

Lists

  • Lists.transform()
  • Lists.partition()
List<Person> personList = Lists.newArrayList(person1,person2,person3,person4);
List<List<Person>> subList = Lists.partition(personList,2);

Sets

  • Sets.filter()
  • Sets.difference()
  • Sets.symmetricDifference()
  • Sets.intersection()
  • Sets.union()
Set<String> s1 = Sets.newHashSet("1","2","3");
Set<String> s2 = Sets.newHashSet("2","3","4");
Sets.difference(s1,s2);  //Would return [1]
Sets.difference(s2,s1); //Would return [4]
Sets.symmetricDifference(s1,s2);// Would return [1,4]
Sets.intersection(s1,s2);//Would return [2,3]
Sets.union(s1,s2);//Would return [1,2,3,4]

Maps

  • Maps.uniqueIndex
//常規寫法
List<Book> books = someService.getBooks();
Map<String,Book> bookMap = new HashMap<String,Book>()
for(Book book : books){
    bookMap.put(book.getIsbn(),book);
}
//guava寫法
List<Book> books = someService.getBooks();
Map<String,Book>bookMap = Maps.uniqueIndex(books.iterator(),new Function<Book, String>(){
      @Override
      public String apply( Book input) {
           return input.getIsbn();
      }
};)
  • Maps.asMap VS Maps.toMap
    Maps.uniqueIndex方法是使用Function從給定值生成鍵,而Maps.asMap方法執行逆操作。 Maps.asMap方法將一組對象用作鍵,並將Function應用於每個鍵對象以生成對應的值。 另一種方法Maps.toMap也採用相同的參數,區別在於返回ImmutableMap而不是map的視圖。 這樣做的重要性在於,從Maps.asMap方法返回的映射將反映對原始映射所做的任何更改,而Maps.toMap方法返回的映射將保持不變。
  • Maps.transformEntries
  • Maps.transformValues

Multimaps

一個Key關聯多個value

ArrayListMultimap

ArrayListMultimap是一個使用ArrayList存儲一個給定key對應的values。可以通過以下方法來創建一個ArrayListMultimap實例:

ArrayListMultimap<String,String> multiMap = ArrayListMultimap.create();
ArrayListMutilmap<String,String> multiMap = ArrayListMultimap.create(numExcpectedKeys,numExpectedValuesPerKey);
ArrayListMulitmap<String,String> mulitMap = ArrayListMultimap.create(listMultiMap);

需要注意ArrayListMultimap.size計算的是所有values累加起來的值,而不是key集合的大小。

ArrayListMultimap不是一個真正的map對象。如果需要執行map接口的方法。可以先執行asMap方法轉換成Map。

 Map<String,Collection<String>> map = multiMap.asMap();

HashMultimap

HashMultimap是基於hash 實現。與ArrayListMultimap不同, HashMultimap不支持多次插入相同的key-value鍵值對。

HashMultimap<String,String> multiMap = HashMultimap.create();
multiMap.put("Bar","1");
multiMap.put("Bar","2");
multiMap.put("Bar","3");
multiMap.put("Bar","3");
multiMap.put("Bar","3");
//上面的multiMap.size大小爲3而不是5.

BiMap

不但可以通過key找到對應的value,反過來也可以通過value找到對應的key。爲了滿足這種操作。map中的value也必須是唯一的。

BiMap<String,String> biMap = HashBiMap.create();
biMap.put("1","Tom");
//This call causes an IllegalArgumentException to be thrown!
biMap.put("2","Tom");

BiMap.forcePut
爲了添加相同的value對應不同的key。可以調用forcePut

@Test
public void testBiMapForcePut() throws Exception {
   BiMap<String,String> biMap = HashBiMap.create();
   biMap.put("1","Tom");
   biMap.forcePut("2","Tom");
   assertThat(biMap.containsKey("1"),is(false));
   assertThat(biMap.containsKey("2"),is(true));
}

BiMap.inverse

 @Test
 public void testBiMapInverse() throws Exception {
           BiMap<String,String> biMap = HashBiMap.create();
           biMap.put("1","Tom");
           biMap.put("2","Harry");
           assertThat(biMap.get("1"),is("Tom"));
           assertThat(biMap.get("2"),is("Harry"));
           BiMap<String,String> inverseMap = biMap.inverse();
           assertThat(inverseMap.get("Tom"),is("1"));
           assertThat(inverseMap.get("Harry"),is("2"));
}

Table

可看作 a map of maps
A table is a collection that takes two keys, a row, and a column, and maps those keys to a single value.

HashBasedTable

HashBasedTable<Integer,Integer,String> table = HashBasedTable.create();
//Creating table with 5 rows and columns initially
HashBasedTable<Integer,Integer,String> table = HashBasedTable.create(5,5);
//Creating a table from an existing table
HashBasedTable<Integer,Integer,String> table = HashBasedTable.create(anotherTable);

Table views

Map<Integer,String> columnMap = table.column(1);
Map<Integer,String> rowMap = table.row(2);

The maps returned are live views and change to columnMap and rowMap, or the original table would be reflected in the other. There are other implementations of the table we should discuss briefly as follows:

  1. ArrayTable is an implementation of the table backed by a two-dimensional array.
  2. There is an ImmutableTable implementation. Since ImmutableTable can’t be updated after it’s created, the row, key, and values are added using ImmutableTable.Builder, which leverages a fluent interface for ease of construction.
  3. A TreeBasedTable table where the row and column keys are ordered, either by the natural order or by specified comparators for the row and column keys.

Range

Range類允許我們使用定義的端點創建特定的時間間隔或值範圍,並使用可比較類型。

Range<Integer> numberRange = Range.closed(1,10);
//both return true meaning inclusive
numberRange.contains(10);
numberRange.contains(1);
Range<Integer> numberRange = Range.open(1,10);
//both return false meaning exclusive
numberRange.contains(10);
numberRange.contains(1);

Ranges with arbitrary comparable objects

Range類實現了Predicate接口
Since Range objects work with any object that implements the Comparable interface, it makes it easy to create a filter for working with only those objects that fall within our desired boundaries. For example, consider the Person class we introduced before:

   public class Person implements Comparable<Person> {
       private String firstName;
       private String lastName;
       private int age;
       private String sex;
       @Override
       public int compareTo(Person o) {
           return ComparisonChain.start().
                  compare(this.firstName,o.getFirstName()).
                  compare(this.lastName,o.getLastName()).
                  compare(this.age,o.getAge()).
                  compare(this.sex,o.getSex()).result();
       }
   }

We would like to create a Range instance for the Person objects where the age is between 35 and 50. But if you look at the compareTo method, we have a slight problem; it includes all the fields in the object. To solve this problem, we are going to leverage the fact that the Range object implements the Predicate interface. Additionally, we are going to use the Predicates.compose method to create a new Predicate composed of Range and Function. First, let’s define our Range instance:

   Range<Integer> ageRange = Range.closed(35,50);

Next, we will create Function that accepts a Person object and returns the age:

Function<Person,Integer> ageFunction = new Function<Person,Integer>() {
   @Override
   public Integer apply(Person person) {
       return person.getAge();
   }
};

Finally, we create our composed Predicate:

Predicate<Person> predicate = Predicates.compose(ageRange,ageFunction);

Now we could have just as easily created a Predicate instance to validate an age range. But by using composition, we can substitute either a new Range object or a new Comparable object. The Range object presents an opportunity to perform powerful operations and make other tasks, for example, filtering, more concise.

Immutable collections

針對前面提到的每一種集合類型,Guava中都提供了相應的不可變集合版本。

Create immutable collection instances
可變和不可變集合在功能方面沒有什麼不同。我們這裏只講述一下生成這兩者實例間的不同。不可變集合通過Builder模式來構造實例。所有的Guava immutable collections都有一個靜態嵌套的Builder類,通過fluent interface approach來創建實例。

 MultiMap<Integer,String> map = new ImmutableListMultimap.Builder<Integer,String>()
   .put(1,"Foo")
   .putAll(2,"Foo","Bar","Baz")
   .putAll(4,"Huey","Duey","Luey")
   .put(3,"Single").build();

Ordering

public abstract class Ordering implements Comparator
集合排序在編程中是一個很重要的話題。 鑑於好的集合抽象對編程至關重要,良好的排序工具亦如此。 Ordering類爲我們提供了有力和簡潔地應用不同排序技術所需的工具。 Ordering是一個抽象類。 儘管它實現了Comparator接口,但Ordering將compare方法聲明爲abstract。

Creating an Ordering instance

有兩種方式創建Ordering實例

  • Creating a new instance and providing an implementation for the compare method.
  • Using the static Ordering.from method that creates an instance of Ordering from an existing Comparator.

Reverse sorting

下面是一個根據城市人口數量排序的Comparator。

public class CityByPopluation implements Comparator<City>{
    @Override
    public int compare(City city1, City city2) {
       return Ints.compare(city1.getPopulation(),city2.getPopulation());
	} 
}

我們通過Ordering和給出的CityByPopluation可以很方便的完成從小到大和從大到小的排序。

//從小到大的排序實例
Ordering.from(cityByPopluation);
//從大到小的排序實例
Ordering.from(cityByPopluation).reverse();

Accounting for null

如果集合中存在元素爲null,那麼該把它們放在前面還是後面。

Ordering.from(comparator).nullsFirst();

在上面的代碼中,我們將null視爲最小值並放在排序好集合的最前面。相對應的方法是Ordering.nullsLast()

Secondary sorting

通常在對對象進行排序時,我們需要處理sorting criterion相等的情況,並定義a secondary sorting criterion來處理。 之前我們定義了Comparator按人口排序City對象,現在我們有另一個Comparator:

public class CityByRainfall implements Comparator<City> {
       @Override
       public int compare(City city1, City city2) {
          return Doubles.compare(city1.getAverageRainfall(),city2.getAverageRainfall()); 
       }
}

上面給出的Comparator是按照城市的降雨量排序。

Ordering.from(cityByPopulation).compound(cityByRainfall);

上面構造了一個先按照城市人口排序,如果人口相等在按照降雨量排序的Ordering實例。下面是一個使用該Ordering實例的例子

 @Test
 public void testSecondarySort(){
    City city1 = cityBuilder.population(100000).averageRainfall(55.0).build();
    City city2 = cityBuilder.population(100000).averageRainfall(45.0).build();
    City city3 = cityBuilder.population(100000).averageRainfall(33.8).build();
    List<City> cities = Lists.newArrayList(city1,city2,city3);
    Ordering<City> secondaryOrdering = Ordering.from(cityByPopulation).compound(cityByRainfall);
    Collections.sort(cities,secondaryOrdering);
    assertThat(cities.get(0),is(city3));
}

Retrieving minimun and maxmun values

Ordering<City> ordering = Ordering.from(cityByPopluation);
//The Ordering.greatestOf method will return the n greatest elements (five greatest elements in this case).
List<City> topFive = ordering.greatestOf(cityList,5);
//returning the n least elements
List<City> bottomThree = ordering.leastOf(cityList,3);
//集合的最大元素
City maxBottom = ordering.max(cityList);
//集合的最小元素
City maxBottom = ordering.min(cityList);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章