Guava: Working with Collections I

1. Classes with useful static methods for working with lists, maps and sets

2. The Range class used to represent the boundaries around a continuous set of values

3. Immutable Collections

4. Bimaps

5. The Table collection type, which is a very powerful collection that is a replacement for using a map of maps.

6. Multimaps, which allow us to have more than one value associated with unique key.

7. The FluentIterable class, which represents a set of powerful interfaces for working with Iterable instances.

8. The Ordering class that gives us enhanced abilities when working with Comparators

 

1. FluentIterable

    The FluentIterable class represents a powerful interface for working with Iterable instances in fluent style of programming.

    The fluent programming style allows us to chain method calls together, making for a more readable code.

    1> FluentIterable.filter(Predicate<T>)

    @Test
    public void filterTest() {
	List<String> list = Lists.newArrayList("A", "B", "C", "D");

	List<String> filteredList = FluentIterable.from(list)
		.filter(Predicates.and(new Predicate<String>() {
		    public boolean apply(String input) {
			return "A".compareTo(input) < 0;
		    }
		}, new Predicate<String>() {
		    public boolean apply(String input) {
			return "D".compareTo(input) > 0;
		    }
		})).toList();

	assertEquals(2, filteredList.size());
	assertEquals("B", filteredList.get(0));
	assertEquals("C", filteredList.get(1));
    }

         source code:

  public static <E> FluentIterable<E> from(final Iterable<E> iterable) {
    return (iterable instanceof FluentIterable) ? (FluentIterable<E>) iterable
        : new FluentIterable<E>(iterable) {
          @Override
          public Iterator<E> iterator() {
            return iterable.iterator();
          }
        };
  }

  FluentIterable(Iterable<E> iterable) {
    this.iterable = checkNotNull(iterable); // set passed in iterable as property
  }

  public final FluentIterable<E> filter(Predicate<? super E> predicate) {
    return from(Iterables.filter(iterable, predicate));
  }

  public static <T> UnmodifiableIterator<T> filter(
      final Iterator<T> unfiltered, final Predicate<? super T> predicate) {
    return new AbstractIterator<T>() {
      @Override protected T computeNext() {
        while (unfiltered.hasNext()) {
          T element = unfiltered.next();
          if (predicate.apply(element)) {
            return element;
          }
        }
        return endOfData();
      }
    };
  }

    2> FluentIterable.transform(Function<F, T>)

    @Test
    public void transformTest() {
	List<String> list = Lists.newArrayList("A", "B", "C", "D", "E");

	Map<String, String> map = Maps.newHashMap();
	map.put("A", "A for Alcohol");
	map.put("B", "B for Boycott");
	map.put("C", "C for Combine");
	List<String> transformedList = FluentIterable.from(list)
		.transform(Functions.forMap(map, "Not Defined")).toList();

	List<String> expectedList = Lists.newArrayList("A for Alcohol",
		"B for Boycott", "C for Combine", "Not Defined", "Not Defined");

	assertEquals(expectedList, transformedList);
    }

        source code:

  public final <T> FluentIterable<T> transform(Function<? super E, T> function) {
    return from(Iterables.transform(iterable, function));
  }

  public static <F, T> Iterable<T> transform(final Iterable<F> fromIterable,
      final Function<? super F, ? extends T> function) {
    return new FluentIterable<T>() {
      @Override
      public Iterator<T> iterator() {
        return Iterators.transform(fromIterable.iterator(), function);
      }
    };
  }

  public static <F, T> Iterator<T> transform(final Iterator<F> fromIterator,
      final Function<? super F, ? extends T> function) {
    return new TransformedIterator<F, T>(fromIterator) {
      @Override
      T transform(F from) {
        return function.apply(from);
      }
    };
  }

 

2. Lists

    1> Lists.newXXXList(): Factory method to simplify the creation of Generic Collection

  public static <E> ArrayList<E> newArrayList(E... elements) {
    int capacity = computeArrayListCapacity(elements.length);
    ArrayList<E> list = new ArrayList<E>(capacity);
    Collections.addAll(list, elements);
    return list;
  }

   2> Lists.partition()

    @Test
    public void partitionTest() {
	List<String> strList = Lists.newArrayList("A", "B", "C", "D");

	List<List<String>> partedStrList = Lists.partition(strList, 2);
	assertEquals(2, partedStrList.size());
	assertEquals(2, partedStrList.get(0).size());
	assertEquals(2, partedStrList.get(1).size());

	partedStrList = Lists.partition(strList, 3);
	assertEquals(2, partedStrList.size());
	assertEquals(3, partedStrList.get(0).size());
	assertEquals(1, partedStrList.get(1).size());
    }

        source code:

  public static <T> List<List<T>> partition(List<T> list, int size) {
    return (list instanceof RandomAccess)
        ? new RandomAccessPartition<T>(list, size)
        : new Partition<T>(list, size);
  }

  private static class Partition<T> extends AbstractList<List<T>> {
    final List<T> list;
    final int size;

    Partition(List<T> list, int size) {
      this.list = list;
      this.size = size;
    }

    @Override public List<T> get(int index) {
      int start = index * size;
      int end = Math.min(start + size, list.size());
      return list.subList(start, end);
    }

    @Override public int size() {
      return IntMath.divide(list.size(), size, RoundingMode.CEILING);
    }

    @Override public boolean isEmpty() {
      return list.isEmpty();
    }
  }

 

3. Sets

    1> Sets.newXXXSet(): Factory method to simplify the creation of Generic Collection

  public static <E> HashSet<E> newHashSet(E... elements) {
    HashSet<E> set = newHashSetWithExpectedSize(elements.length);
    Collections.addAll(set, elements);
    return set;
  }

    2> Sets.difference and Sets.intersection and Sets.union

    @Test
    public void partitionTest() {
	Set<String> strSet1 = Sets.newHashSet("A", "B", "C", "D");
	Set<String> strSet2 = Sets.newHashSet("D", "M", "O", "G");
	Set<String> diffSet = Sets.difference(strSet1, strSet2);
	assertEquals(3, diffSet.size());

	Set<String> interSet = Sets.intersection(strSet1, strSet2);
	assertEquals(1, interSet.size());

	Set<String> unionSet = Sets.union(strSet1, strSet2);
	assertEquals(7, unionSet.size());
    }

        source code:

  public static <E> SetView<E> difference(
      final Set<E> set1, final Set<?> set2) {

    final Predicate<Object> notInSet2 = Predicates.not(Predicates.in(set2));
    return new SetView<E>() {
      @Override public Iterator<E> iterator() {
        return Iterators.filter(set1.iterator(), notInSet2);
      }
      @Override public int size() {
        return Iterators.size(iterator());
      }
      @Override public boolean isEmpty() {
        return set2.containsAll(set1);
      }
      @Override public boolean contains(Object element) {
        return set1.contains(element) && !set2.contains(element);
      }
    };
  }
  public static <E> SetView<E> intersection(
      final Set<E> set1, final Set<?> set2) {

    final Predicate<Object> inSet2 = Predicates.in(set2);
    return new SetView<E>() {
      @Override public Iterator<E> iterator() {
        return Iterators.filter(set1.iterator(), inSet2);
      }
      @Override public int size() {
        return Iterators.size(iterator());
      }
      @Override public boolean isEmpty() {
        return !iterator().hasNext();
      }
      @Override public boolean contains(Object object) {
        return set1.contains(object) && set2.contains(object);
      }
      @Override public boolean containsAll(Collection<?> collection) {
        return set1.containsAll(collection)
            && set2.containsAll(collection);
      }
    };
  }
  public static <E> SetView<E> union(
      final Set<? extends E> set1, final Set<? extends E> set2) {

    final Set<? extends E> set2minus1 = difference(set2, set1);

    return new SetView<E>() {
      @Override public int size() {
        return set1.size() + set2minus1.size();
      }
      @Override public boolean isEmpty() {
        return set1.isEmpty() && set2.isEmpty();
      }
      @Override public Iterator<E> iterator() {
        return Iterators.unmodifiableIterator(
            Iterators.concat(set1.iterator(), set2minus1.iterator()));
      }
      @Override public boolean contains(Object object) {
        return set1.contains(object) || set2.contains(object);
      }
      @Override public <S extends Set<E>> S copyInto(S set) {
        set.addAll(set1);
        set.addAll(set2);
        return set;
      }
      @Override public ImmutableSet<E> immutableCopy() {
        return new ImmutableSet.Builder<E>()
            .addAll(set1).addAll(set2).build();
      }
    };
  }

 

4. Maps

    1> Maps.newXXXMap()

    2> Maps.uniqueIndex(Iterator<V>, Function<V, K>)

    @Test
    public void traditionalTest() {
	List<Person> personList = Lists.newArrayList(new Person("Davy", "Male",
		24), new Person("Calypso", "Female", 22));
	Map<String, Person> map = Maps.newHashMap();
	for (Person p : personList) {
	    map.put(p.getName(), p);
	}

	assertEquals(2, map.size());
    }

    @Test
    public void uniqueIndexTest() {
	List<Person> personList = Lists.newArrayList(new Person("Davy", "Male",
		24), new Person("Calypso", "Female", 22));
	Map<String, Person> map = Maps.uniqueIndex(personList,
		new Function<Person, String>() {
		    public String apply(Person input) {
			return input.getName();
		    }
		});

	assertEquals(2, map.size());
    }

    class Person {
	String name;
	String gender;
	int age;

	public Person(String name, String gender, int age) {
	    super();
	    this.name = name;
	    this.gender = gender;
	    this.age = age;
	}

	public String getName() {
	    return name;
	}

	public String getGender() {
	    return gender;
	}

	public int getAge() {
	    return age;
	}

	@Override
	public String toString() {
	    return "Person [name=" + name + ", gender=" + gender + ", age="
		    + age + "]";
	}
    }

        source code:

  public static <K, V> ImmutableMap<K, V> uniqueIndex(
      Iterable<V> values, Function<? super V, K> keyFunction) {
    return uniqueIndex(values.iterator(), keyFunction);
  }

  public static <K, V> ImmutableMap<K, V> uniqueIndex(
      Iterator<V> values, Function<? super V, K> keyFunction) {
    ImmutableMap.Builder<K, V> builder = ImmutableMap.builder();
    while (values.hasNext()) {
      V value = values.next();
      builder.put(keyFunction.apply(value), value);
    }
    return builder.build();
  }

    3> Maps.asMap(Set<K>, Function<K, V>)

    The Maps.asMap method takes a set of objects to be used as keys, and Function is applied to each key to generate the value for entry into a map instance.

    @Test
    public void asMapTest() {
	Set<String> nameSet = Sets.newHashSet("Davy", "Calypso");
	Map<String, Person> map = Maps.asMap(nameSet,
		new Function<String, Person>() {
		    public Person apply(String name) {
			return new Person(name, "UNKNOWN", 0);
		    }
		});
	assertEquals(2, map.size());
    }

    4> Maps.transformEntries

    @Test
    public void transformEntriesTest() {
	Map<String, Person> personMap = Maps.newHashMap();
	personMap.put("Davy", new Person("Davy", "Male", 24));
	personMap.put("Calypso", new Person("Calypso", "Female", 22));
	Map<String, People> peopleMap = Maps.transformEntries(personMap,
		new EntryTransformer<String, Person, People>() {
		    public People transformEntry(String key, Person value) {
			return new People(value.getName(), value.getGender());
		    }
		});
	assertEquals(2, peopleMap.size());
    }

 

5. Multimaps

    1> ArrayListMultimap = HashMap<K, ArrayList<V>>

    2> HashMultimap = HashMap<K, HashSet<V>>

    3> LinkedHashMultimap = LinkedHashMap<K, LinkedHashSet<V>>

    4> TreeMultimap = TreeMap<K, TreeSet<V>>

    5> LinkedListMultimap = HashMap<K, LinkedList<V>>

         Q: Why the realization of LinkedListMultimap is different from others' ?

              Why don't they simply extends AbstractListMultimap and then generalize method createCollection() ?

 

6. Exercises:

    1> Filter Lists

    @Test
    public void filterListTest() {
	List<String> list = Lists.newArrayList("A", "B", "C", "D");
	List<String> filteredList = FluentIterable.from(list)
		.filter(new Predicate<String>() {
		    @Override
		    public boolean apply(String input) {
			return "A".compareTo(input) < 0;
		    }
		}).toList();
	List<String> expectedList = Lists.newArrayList("B", "C", "D");
	assertEquals(expectedList, filteredList);

	List<Object> objList = Lists.<Object> newArrayList("A", "B",
		new Double(1.2), new Double(1.0));
	List<Double> doubleList = FluentIterable.from(objList)
		.filter(Double.class).toList();
	List<Double> expDoubleList = Lists.newArrayList(new Double(1.2),
		new Double(1.0));
	assertEquals(expDoubleList, doubleList);
    }

    2> Transform Lists

    @Test
    public void transformListTest() {
	List<String> list = Lists.newArrayList("A", "B", "C", "D");
	List<String> transformedList = FluentIterable.from(list)
		.transform(new Function<String, String>() {
		    @Override
		    public String apply(String input) {
			return input.concat("-Postfix");
		    }
		}).toList();
	List<String> expectedList = Lists.newArrayList("A-Postfix",
		"B-Postfix", "C-Postfix", "D-Postfix");
	assertEquals(expectedList, transformedList);

	transformedList = FluentIterable.from(list)
		.filter(new Predicate<String>() {
		    @Override
		    public boolean apply(String input) {
			return !"A".equals(input);
		    }
		}).transformAndConcat(new Function<String, Iterable<String>>() {
		    @Override
		    public Iterable<String> apply(String input) {
			return Lists.newArrayList(input,
				input.concat("-Postfix"));
		    }
		}).toList();
	expectedList = Lists.newArrayList("B", "B-Postfix", "C", "C-Postfix",
		"D", "D-Postfix");
	assertEquals(expectedList, transformedList);
    }

    3> Filter Map

    @Test
    public void filterMapTest() {
	Map<String, String> map = Maps.newHashMap();
	map.put("A", "A for Alcohol");
	map.put("B", "B for Boycott");
	map.put("C", "C for Cowboy");
	map.put("D", "D for Dodge");

	Map<String, String> filteredMap = Maps.filterEntries(map,
		new Predicate<Map.Entry<String, String>>() {
		    @Override
		    public boolean apply(Entry<String, String> input) {
			return "A".equals(input.getKey())
				&& "A for Alcohol".equals(input.getValue());
		    }
		});
	Map<String, String> expectedMap = Maps.newHashMap();
	expectedMap.put("A", "A for Alcohol");
	assertEquals(expectedMap, filteredMap);

	filteredMap = Maps.filterKeys(map, new Predicate<String>() {
	    @Override
	    public boolean apply(String input) {
		return input.equals("B");
	    }
	});
	expectedMap = Maps.newHashMap();
	expectedMap.put("B", "B for Boycott");
	assertEquals(expectedMap, filteredMap);

	filteredMap = Maps.filterValues(map, new Predicate<String>() {
	    @Override
	    public boolean apply(String input) {
		return input.equals("C for Cowboy");
	    }
	});
	expectedMap = Maps.newHashMap();
	expectedMap.put("C", "C for Cowboy");
	assertEquals(expectedMap, filteredMap);
    }

    4> Transform Map

    @Test
    public void transformMapTest() {
	Map<String, String> map = Maps.newHashMap();
	map.put("A", "A for Alcohol");
	map.put("B", "B for Boycott");
	map.put("C", "C for Cowboy");
	map.put("D", "D for Dodge");

	Map<String, Person> transformedMap = Maps.transformValues(map,
		new Function<String, Person>() {
		    @Override
		    public Person apply(String input) {
			return new Person(input);
		    }
		});
	Map<String, Person> expectedMap = Maps.newHashMap();
	expectedMap.put("A", new Person("A for Alcohol"));
	expectedMap.put("B", new Person("B for Boycott"));
	expectedMap.put("C", new Person("C for Cowboy"));
	expectedMap.put("D", new Person("D for Dodge"));
	assertEquals(expectedMap, transformedMap);

	transformedMap = Maps.transformEntries(map,
		new EntryTransformer<String, String, Person>() {
		    @Override
		    public Person transformEntry(String key, String value) {
			return "A".equals(key) ? new Person(key) : new Person(
				value);
		    }
		});
	expectedMap = Maps.newHashMap();
	expectedMap.put("A", new Person("A"));
	expectedMap.put("B", new Person("B for Boycott"));
	expectedMap.put("C", new Person("C for Cowboy"));
	expectedMap.put("D", new Person("D for Dodge"));
	assertEquals(expectedMap, transformedMap);
    }

    5> Add element into ImmutableList/ImmutableSet/ImmutableMap

    @Test
    public void test() {
	List<String> list = Lists.newArrayList("A", "B", "C", "D", "E");

	List<String> filteredList = FluentIterable.from(list)
		.filter(new Predicate<String>() {
		    @Override
		    public boolean apply(String input) {
			return "A".equals(input) || "D".equals(input);
		    }
		}).toList();

	filteredList = ImmutableList.<String> builder().addAll(filteredList)
		.add("F").build();

	assertEquals(Lists.newArrayList("A", "D", "F"), filteredList);
    }
    @Test
    public void test2() {
	Function<String, String> postfixFunction = new Function<String, String>() {
	    @Override
	    public String apply(String input) {
		return input.concat("-Postfix");
	    }
	};
	Map<String, String> map = Maps.toMap(
		Lists.newArrayList("A", "B", "C", "D"), postfixFunction);

	Map<String, String> buildedMap = ImmutableMap
		.<String, String> builder().putAll(map).put("E", "E-Postfix")
		.build();

	assertEquals(Maps.toMap(Lists.newArrayList("A", "B", "C", "D", "E"),
		postfixFunction), buildedMap);
    }

    Q: Why don't they return MutableCollection/MutableMap instead of ImmutableCollction/ImmutableMap for handy future manipulation(add/remove)?

 

Reference Links:
1) Getting Started with Google Guava -Bill Bejeck

2) http://stackoverflow.com/questions/12937938/adding-and-removing-items-to-a-guava-immutablelist

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值