Guava 对 JDK 集合的扩展,这是 Guava 最成熟和为人所知的部分
本文主要通过例子的方式简单介绍了一下集合的使用以及需要注意的一些细节。
如果希望了解更多的细节,可以可以查看目录中的链接进行查看。
— By Syahfozy
1 不可变集合: 用不变的集合进行防御性编程和性能提升。
2 新集合类型: multisets, multimaps, tables, bidirectional maps 等
3 强大的集合工具类: 提供 java.util.Collections 中没有的集合工具
4 扩展工具类:让实现和扩展集合类变得更容易,比如创建 Collection 的装饰器,或实现迭代器
一、不可变集合
重要提示:所有Guava不可变集合的实现都不接受null值。我们对Google内部的代码库做过详细研究,发现只有5%的情况需要在集合中允许null元素,剩下的95%场景都是遇到null值就快速失败。如果你需要在不可变集合中使用null,请使用JDK中的Collections.unmodifiableXXX方法。更多细节建议请参考“使用和避免null”。
1. 创建方法
对有序不可变集合来说,排序是在构造集合的时候完成的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Set<String> colors = Sets.newHashSet("red", "orange", "yellow"); Set<Color> colorSet = Sets.newHashSet(new Color(0, 0, 0));
ImmutableSet.copyOf(colors);
ImmutableSet.of(colors); ImmutableSet.of("red", "orange", "yellow"); ImmutableMap.of("a", 1, "b", 2);
ImmutableSet<Color> GOOGLE_COLORS = ImmutableSet.<Color>builder() .addAll(colorSet) .add(new Color(0, 191, 255)) .build();
|
2. 使用方法
1 2 3 4 5 6 7 8 9
| ImmutableSet<String> colors = ImmutableSet.of("red", "orange", "yellow");
ImmutableList.copyOf(colors);
ImmutableList immutableList = colors.asList();
|
细节:关联可变集合和不可变集合
二、新集合类型
Guava引入了很多JDK没有的、但我们发现明显有用的新集合类型。这些新类型是为了和JDK集合框架共存,而没有往JDK集合抽象中硬塞其他概念。作为一般规则,Guava集合非常精准地遵循了JDK接口契约
1. Multiset
- 可以多次添加相等的元素的集合
- 可以理解为没有元素顺序限制的ArrayList,Map<E, Integer>,键为元素,值为计数
Guava提供了一个新集合类型 Multiset,它可以多次添加相等的元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
System.out.println(hashMultiset.add("a"));
System.out.println(hashMultiset.remove("a"));
System.out.println(hashMultiset.iterator().next());
System.out.println(hashMultiset.size());
System.out.println(hashMultiset.count("a"));
System.out.println(hashMultiset.setCount("c", 2));
System.out.println(hashMultiset.entrySet());
System.out.println(hashMultiset.elementSet());
|
Guava提供了多种Multiset的实现,如
Map |
对应的Multiset |
是否支持null元素 |
HashMap |
HashMultiset |
是 |
TreeMap |
TreeMultiset |
是(如果comparator支持的话) |
LinkedHashMap |
LinkedHashMultiset |
是 |
ConcurrentHashMap |
ConcurrentHashMultiset |
否 |
ImmutableMap |
ImmutableMultiset |
否 |
2. Multimap
Multimap可以把键映射到任意多个值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| System.out.println(multimap.get("c"));
System.out.println(multimap.asMap());
multimap.remove("b", "ss"); System.out.println(multimap.containsKey("b"));
System.out.println(multimap.entries());
System.out.println(multimap.asMap().entrySet());
System.out.println(multimap.size());
System.out.println(multimap.asMap().size());
|
Multimap 提供了多种形式的实现。在大多数要使用 Map<K, Collection> 的地方,你都可以使用它们,即把键映射到任意多个值的一般方式:
实现 |
键行为类似 |
值行为类似 |
ArrayListMultimap |
HashMap |
ArrayList |
HashMultimap |
HashMap |
HashSet |
LinkedListMultimap* |
LinkedHashMap* |
LinkedList* |
LinkedHashMultimap** |
LinkedHashMap |
LinkedHashMap |
TreeMultimap |
TreeMap |
TreeSet |
ImmutableListMultimap |
ImmutableMap |
ImmutableList |
ImmutableSetMultimap |
ImmutableMap |
ImmutableSet |
3. BiMap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
public static void biMap() {
BiMap<String, Integer> userId = HashBiMap.create(); userId.put("a", 123);
userId.forcePut("b", 123); System.out.println(userId);
System.out.println(userId.inverse().get(123));
Set<Integer> IdSet = userId.values(); System.out.println(IdSet);
}
|
BiMap的各种实现
键–值实现 |
值–键实现 |
对应的BiMap实现 |
HashMap |
HashMap |
HashBiMap |
ImmutableMap |
ImmutableMap |
ImmutableBiMap |
EnumMap |
EnumMap |
EnumBiMap |
EnumMap |
HashMap |
EnumHashBiMap |
4. Table
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
public static void table() { Table<Integer, Integer, Double> weightedGraph = HashBasedTable.create(); weightedGraph.put(1, 2, 4d); weightedGraph.put(1, 3, 20d); weightedGraph.put(2, 3, 5d); System.out.println(weightedGraph);
Map<Integer, Map<Integer, Double>> map = weightedGraph.rowMap(); System.out.println(map);
Set<Integer> set = weightedGraph.rowKeySet(); System.out.println(set);
Map<Integer, Double> row = weightedGraph.row(2); System.out.println(set); row.put(4, 6d); row.put(5, 8d); System.out.println(weightedGraph);
Set<Table.Cell<Integer, Integer, Double>> cells = weightedGraph.cellSet(); System.out.println(cells);
}
|
5. ClassToInstanceMap
ClassToInstanceMap是一种特殊的Map:它的键是类型,而值是符合键所指类型的对象
对于ClassToInstanceMap,Guava提供了两种有用的实现:MutableClassToInstanceMap和 ImmutableClassToInstanceMap
1 2 3 4 5 6 7 8 9
| public static void classToInstanceMap() {
ClassToInstanceMap<Number> numberDefaults=MutableClassToInstanceMap.create(); numberDefaults.putInstance(Integer.class, Integer.valueOf(0));
Integer instance = numberDefaults.getInstance(Integer.class); System.out.println(instance);
}
|
6. RangeSet
RangeSet描述了一组不相连的、非空的区间
当把一个区间添加到可变的RangeSet时,所有相连的区间会被合并,空区间会被忽略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public static void rangeSet() { RangeSet<Integer> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(1, 10)); System.out.println(rangeSet.toString());
rangeSet.add(Range.closedOpen(11, 15)); System.out.println(rangeSet.toString());
rangeSet.add(Range.closedOpen(15, 20)); System.out.println(rangeSet.toString());
rangeSet.add(Range.openClosed(0, 0)); System.out.println(rangeSet.toString());
rangeSet.remove(Range.open(5, 10)); System.out.println(rangeSet.toString());
}
|
RangeSet 的实现支持非常广泛的视图:
- complement():返回 RangeSet 的补集视图。complement 也是 RangeSet 类型, 包含了不相连的、非空的区间。
- subRangeSet(Range):返回 RangeSet 与给定 Range 的交集视图。这扩展了传统排序集合中的 headSet、subSet 和 tailSet 操作。
- asRanges():用 Set<Range> 表现 RangeSet,这样可以遍历其中的 Range。
- asSet(DiscreteDomain)(仅 ImmutableRangeSet 支持):用 ImmutableSortedSet 表现 RangeSet,以区间中所有元素的形式而不是区间本身的形式查看。(这个操作不支持 DiscreteDomain 和 RangeSet 都没有上边界,或都没有下边界的情况)
RangeSet 的查询方法
为了方便操作,RangeSet 直接提供了若干查询方法,其中最突出的有:
- contains(C):RangeSet 最基本的操作,判断 RangeSet 中是否有任何区间包含给定元素。
- rangeContaining(C):返回包含给定元素的区间;若没有这样的区间,则返回 null。
- encloses(Range):简单明了,判断 RangeSet 中是否有任何区间包括给定区间。
- span():返回包括 RangeSet 中所有区间的最小区间。
7. RangeMap
RangeMap描述了”不相交的、非空的区间”到特定值的映射
和RangeSet不同,RangeMap不会合并相邻的映射,即便相邻的区间映射到相同的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public static void rangeMap() { RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
rangeMap.put(Range.closed(1, 10), "foo"); System.out.println(rangeMap.toString());
rangeMap.put(Range.open(3, 6), "bar"); System.out.println(rangeMap.toString());
rangeMap.put(Range.open(10, 20), "foo"); System.out.println(rangeMap.toString());
rangeMap.remove(Range.closed(5, 11)); System.out.println(rangeMap.toString());
Map<Range<Integer>, String> mapOfRanges = rangeMap.asMapOfRanges(); System.out.println(mapOfRanges);
RangeMap<Integer, String> subRangeMap = rangeMap.subRangeMap(Range.open(12, 18)); System.out.println(subRangeMap); }
|
三、集合工具类
任何对JDK集合框架有经验的程序员都熟悉和喜欢java.util.Collections包含的工具方法。Guava沿着这些路线提供了更多的工具方法:适用于所有集合的静态方法。这是Guava最流行和成熟的部分之一。
我们用相对直观的方式把工具类与特定集合接口的对应关系归纳如下:
1. 静态工厂方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public static void staticConstructors() {
List<Integer> list = Lists.newArrayList(); Map<String, String> map = Maps.newLinkedHashMap();
Set<Integer> copySet = Sets.newHashSet(1, 2); List<String> theseElements = Lists.newArrayList("alpha", "beta", "gamma");
List<Integer> exactly100 = Lists.newArrayListWithCapacity(100); List<Integer> approx100 = Lists.newArrayListWithExpectedSize(100); Set<Integer> approx100Set = Sets.newHashSetWithExpectedSize(100);
Multiset<String> multiset = HashMultiset.create();
}
|
2. Iterables工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
| public static void iterable() {
Iterable<Integer> concatenated = Iterables.concat( Ints.asList(1, 2, 3), Ints.asList(4, 5, 6)); System.out.println(concatenated);
int num = Iterables.frequency(concatenated, 1); System.out.println(num);
Iterable<List<Integer>> partition = Iterables.partition(concatenated, 2); System.out.println(partition);
int firstValue = Iterables.getFirst(concatenated, 0); System.out.println(firstValue);
int lastValue = Iterables.getLast(concatenated, 0); System.out.println(lastValue);
Iterable<Integer> other = Iterables.concat( Ints.asList(4, 5, 6), Ints.asList(1, 2, 3)); System.out.println(other); boolean same = Iterables.elementsEqual(concatenated, other); System.out.println(same);
Iterable<Integer> unmodifiableIterable = Iterables.unmodifiableIterable(concatenated); System.out.println(unmodifiableIterable);
Iterable<Integer> limitIterable = Iterables.limit(concatenated, 1); System.out.println(limitIterable);
int value = Iterables.getOnlyElement(limitIterable); System.out.println(value);
List numbers = Lists.newArrayList(-1, 0);
Iterables.addAll(numbers, concatenated); System.out.println(numbers);
boolean contains = Iterables.contains(concatenated, 1); System.out.println(contains);
boolean removeAll = Iterables.removeAll(numbers, Lists.newArrayList(6, 9)); System.out.println(removeAll); System.out.println(numbers);
numbers = Lists.newArrayList(-1, 0); boolean retainAll = Iterables.retainAll(numbers, Lists.newArrayList(0)); System.out.println(retainAll); System.out.println(numbers);
int size = Iterables.size(concatenated); System.out.println(size);
Integer[] array = Iterables.toArray(concatenated, Integer.class); for (Integer integer : array) { System.out.print(integer + " "); } System.out.println();
boolean isEmpty = Iterables.isEmpty(Lists.newArrayList()); System.out.println(isEmpty);
int one = Iterables.get(concatenated, 1); System.out.println(one);
String str = Iterables.toString(concatenated); System.out.println(str); }
|
3. Lists工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
public static void lists() {
List countUp = Ints.asList(1, 2, 3, 4, 5);
List countDown = Lists.reverse(countUp); System.out.println(countDown);
List<List> parts = Lists.partition(countUp, 2); System.out.println(countDown);
List list1 = Lists.newArrayList(); List list2 = Lists.newArrayList(1, 2); List list3 = Lists.newArrayList(Iterables.concat()); List list4 = Lists.newArrayList(Ints.asList(1).iterator()); List list5 = Lists.newArrayListWithCapacity(10); List list6 = Lists.newArrayListWithExpectedSize(10);
LinkedList<Integer> linkedList1 = Lists.newLinkedList(); LinkedList linkedList2 = Lists.newLinkedList(Iterables.concat());
}
|
4. Sets工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
|
Set<String> wordsWithPrimeLength = ImmutableSet.of("one", "two", "three", "six", "seven", "eight"); Set<String> primes = ImmutableSet.of("two", "three", "five", "seven");
Sets.SetView<String> intersection = Sets.intersection(primes, wordsWithPrimeLength);
System.out.println(intersection);
Sets.SetView<String> union = Sets.union(primes, wordsWithPrimeLength);
System.out.println(union);
Sets.SetView<String> difference = Sets.difference(wordsWithPrimeLength, primes); Sets.SetView<String> difference2 = Sets.difference(primes, wordsWithPrimeLength);
System.out.println(difference);
System.out.println(difference2);
Sets.SetView<String> symmetricDifference = Sets.symmetricDifference(wordsWithPrimeLength, primes); Sets.SetView<String> symmetricDifference2 = Sets.symmetricDifference(primes, wordsWithPrimeLength);
System.out.println(symmetricDifference);
System.out.println(symmetricDifference2);
Set<String> animals = ImmutableSet.of("gerbil", "hamster"); Set<String> fruits = ImmutableSet.of("apple", "orange", "banana");
Set<List<String>> product = Sets.cartesianProduct(animals, fruits);
System.out.println(product);
Set<Set<String>> animalSets = Sets.powerSet(animals);
animalSets.forEach(v -> System.out.print(v + " ")); System.out.println();
ImmutableSet<String> immutableCopy = intersection.immutableCopy();
System.out.println(immutableCopy);
Set<String> set = intersection.copyInto(Sets.newHashSet("one"));
System.out.println(set);
ch01_basic Set<Integer> hashSet1 = Sets.newHashSet();
Set<Integer> hashSet2 = Sets.newHashSet(1, 2);
Set<Integer> hashSet3 = Sets.newHashSet(Iterables.concat());
Set<Integer> hashSet4 = Sets.newHashSet(Ints.asList().iterator());
Set<Integer> hashSet5 = Sets.newHashSetWithExpectedSize(10);
ch01_basic Set<Integer> linkedHashSet1 = Sets.newLinkedHashSet();
Set<Integer> linkedHashSet2 = Sets.newLinkedHashSet(Iterables.concat());
Set<Integer> linkedHashSet3 = Sets.newLinkedHashSetWithExpectedSize(10);
ch01_basic Set<Integer> treeSet1 = Sets.newTreeSet();
Set<Integer> treeSet2 = Sets.newTreeSet(Iterables.concat());
Set<Integer> treeSet3 = Sets.newTreeSet(Comparator.comparingInt(o -> o)); treeSet3.addAll(Ints.asList(1, 2, 3));
System.out.println(treeSet3);
treeSet3 = Sets.newTreeSet((o1, o2) -> o2 - o1); treeSet3.addAll(Ints.asList(1, 2, 3));
System.out.println(treeSet3);
|
5. Maps工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
List<String> ch06_strings = Lists.newArrayList("aaa", "bb"); ImmutableMap<Integer, String> stringsByIndex = Maps.uniqueIndex(ch06_strings, new Function<String, Integer>() { public Integer apply(String string) { return string.length(); } });
Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3); Map<String, Integer> right = ImmutableMap.of("b", 2, "c", 4, "d", 5); MapDifference<String, Integer> diff = Maps.difference(left, right);
Map<String, Integer> entriesInCommon = diff.entriesInCommon();
System.out.println(entriesInCommon);
Map<String, MapDifference.ValueDifference<Integer>> entriesDiffering = diff.entriesDiffering();
System.out.println(entriesDiffering);
Map<String, Integer> entriesOnlyOnLeft = diff.entriesOnlyOnLeft();
System.out.println(entriesOnlyOnLeft);
Map<String, Integer> entriesOnlyOnRight = diff.entriesOnlyOnRight();
System.out.println(entriesOnlyOnRight);
BiMap<Integer, String> logfileMap = HashBiMap.create(); logfileMap.put(1,"a.log"); logfileMap.put(2,"b.log");
BiMap<Integer, String> synchronizedBiMap = Maps.synchronizedBiMap(logfileMap);
BiMap<Integer, String> unmodifiableBiMap = Maps.unmodifiableBiMap(logfileMap);
Map<String, String> hashMap1 = Maps.newHashMap();
Map<String, String> hashMap2 = Maps.newHashMap(Maps.newHashMap());
Map<String, String> hashMap3 = Maps.newHashMapWithExpectedSize(10);
Map<String, String> linkedHashMap1 = Maps.newLinkedHashMap();
Map<String, String> linkedHashMap2 = Maps.newLinkedHashMap(Maps.newHashMap());
Map<String, String> treeMap1 = Maps.newTreeMap();
Map<String, String> treeMap2 = Maps.newTreeMap(new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.length() - o2.length(); } });
Map<String, String> treeMap3 = Maps.newTreeMap(Maps.newTreeMap());
Map<DayOfWeek, Integer> map = Maps.newEnumMap(DayOfWeek.class); map.put(MONDAY, 1);
EnumMap enumMap = new EnumMap(ImmutableMap.of(MONDAY, 1)); enumMap.put(TUESDAY, 2);
ConcurrentMap<String, String> concurrentHashMap = Maps.newConcurrentMap();
IdentityHashMap<String, String> identityHashMap1 = Maps.newIdentityHashMap(); identityHashMap1.put(new String("yyy"), "1"); identityHashMap1.put(new String("yyy"), "2"); identityHashMap1.put(new String("xxx"), "3");
System.out.println(identityHashMap1);
IdentityHashMap<String, String> identityHashMap2 = Maps.newIdentityHashMap(); identityHashMap2.put("yyy", "1"); identityHashMap2.put("yyy", "2"); identityHashMap2.put("xxx", "3");
System.out.println(identityHashMap2);
|
6. Multisets工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
|
ImmutableSet<String> digits = ImmutableSet.of( "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"); ImmutableListMultimap<Integer, String> digitsByLength = Multimaps.index(digits, string -> string.length()); System.out.println(digitsByLength);
ArrayListMultimap<String, Integer> multimap = ArrayListMultimap.create(); multimap.putAll("b", Ints.asList(2, 4, 6)); multimap.putAll("a", Ints.asList(4, 2, 1)); multimap.putAll("c", Ints.asList(2, 5, 3));
TreeMultimap<Integer, String> inverse = Multimaps.invertFrom(multimap, TreeMultimap.create()); System.out.println(inverse);
ImmutableMultimap inverse2 = ImmutableMultimap.of( "b", Ints.asList(2, 4, 6), "a", Ints.asList(4, 2, 1), "c", Ints.asList(2, 5, 3)); System.out.println(inverse2.inverse());
Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 1, "c", 2);
SetMultimap<String, Integer> setMultimap = Multimaps.forMap(map); System.out.println(setMultimap);
Multimap<Integer, String> inverseMap = Multimaps.invertFrom(setMultimap, HashMultimap.create()); System.out.println(inverseMap);
|
7. 包装器
8. Tables工具类
四、集合扩展工具类
1. Forwarding装饰器
通过创建ForwardingXXX的子类并实现delegate()方法,可以选择性地覆盖子类的方法来增加装饰功能,而不需要自己委托每个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| AddLoggingList<Integer> loggingList = new AddLoggingList<>(); loggingList.add(1);
class AddLoggingList<E> extends ForwardingList<E> { final List<E> delegate = Lists.newArrayList(); @Override protected List<E> delegate() { return delegate; } @Override public void add(int index, E elem) { log(index, elem); super.add(index, elem); } @Override public boolean add(E elem) { return standardAdd(elem); } @Override public boolean addAll(Collection<? extends E> c) { return standardAddAll(c); }
private void log(int index, E elem) { System.out.println(String.format("add %s in %d", elem, index)); } }
|
2. PeekingIterator
Iterators提供一个Iterators.peekingIterator(Iterator)方法,来把Iterator包装为PeekingIterator,这是Iterator的子类,它能让你事先窥视[peek()]到下一次调用next()返回的元素。
注意:Iterators.peekingIterator返回的PeekingIterator不支持在peek()操作之后调用remove()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
List<Integer> numbers = Ints.asList(1, 1, 2, 3, 3); List<Integer> results = Lists.newArrayList();
PeekingIterator<Integer> iterator = Iterators.peekingIterator(numbers.iterator()); while (iterator.hasNext()) { Integer current = iterator.next(); while (iterator.hasNext() && iterator.peek().equals(current)) { iterator.next(); } results.add(current); }
System.out.println(results);
|
3. AbstractIterator
实现自己的Iterator, 例如包装一个iterator跳过长度为1的字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| Iterator<String> skipNulls2 = skipSingle(Lists.newArrayList("aa", "b", "cc").iterator());
while (skipNulls2.hasNext()) { System.out.print(skipNulls2.next() + " "); }
public static Iterator<String> skipSingle(final Iterator<String> in) { return new AbstractIterator<String>() { protected String computeNext() { while (in.hasNext()) { String s = in.next(); if (s.length() > 1) { return s; } } return endOfData(); } }; }
|