Guava-Working with Collections

文章目录

  • The FluentIterable class
  • Lists
  • Sets
  • Maps
  • Multimaps
    • ArrayListMultimap
    • HashMultimap
  • BiMap
  • Table
    • HashBasedTable
    • Table views
  • Range
    • Ranges with arbitrary comparable objects
  • Immutable collections
  • Ordering
    • Creating an Ordering instance
    • Reverse sorting
    • Accounting for null
    • Secondary sorting
    • Retrieving minimun and maxmun values

The FluentIterable class

  • FluentIterable.from(final Iterable iterable)
  • FluentIterable.filter(Predicate predicate)
  • FluentIterable.transform(Function 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);

你可能感兴趣的:(读书笔记)