如果你不想收集元素
问题的标题是从流中collect对,所以我假设你想实际收集这些,但你评论说:
您的解决方案有效,问题在于它将数据从文件加载到 PairList,然后我可以使用该集合中的流来处理对。我不能这样做,因为数据可能太大而无法存储在内存中。
所以这是一种不收集元素的方法。
将 Iterator 转换为 Iterator>
相对简单,然后将流转换为对流。
/**
* Returns an iterator over pairs of elements returned by the iterator.
*
* @param iterator the base iterator
* @return the paired iterator
*/
public static <T> Iterator<List<T>> paired(Iterator<T> iterator) {
return new Iterator<List<T>>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public List<T> next() {
T first = iterator.next();
if (iterator.hasNext()) {
return Arrays.asList(first, iterator.next());
} else {
return Arrays.asList(first);
}
}
};
}
/**
* Returns an stream of pairs of elements from a stream.
*
* @param stream the base stream
* @return the pair stream
*/
public static <T> Stream<List<T>> paired(Stream<T> stream) {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(paired(stream.iterator()), Spliterator.ORDERED),
false);
}
@Test
public void iteratorAndStreamsExample() {
List<String> strings = Arrays.asList("a", "b", "c", "d", "e", "f");
Iterator<List<String>> pairs = paired(strings.iterator());
while (pairs.hasNext()) {
System.out.println(pairs.next());
// [a, b]
// [c, d]
// [e, f]
}
paired(Stream.of(1, 2, 3, 4, 5, 6, 7, 8)).forEach(System.out::println);
// [1, 2]
// [3, 4]
// [5, 6]
// [7, 8]
}
如果你想收集元素...
我会通过收集到一个列表中来做到这一点,并使用 AbstractList 以成对的形式提供元素的视图。
首先,PairList。这是一个包含偶数个元素的 any 列表的简单 AbstractList 包装器。 (一旦指定了所需的行为,这可以很容易地适应处理奇数长度的列表。)
/**
* A view on a list of its elements as pairs.
*
* @param <T> the element type
*/
static class PairList<T> extends AbstractList<List<T>> {
private final List<T> elements;
/**
* Creates a new pair list.
*
* @param elements the elements
*
* @throws NullPointerException if elements is null
* @throws IllegalArgumentException if the length of elements is not even
*/
public PairList(List<T> elements) {
Objects.requireNonNull(elements, "elements must not be null");
this.elements = new ArrayList<>(elements);
if (this.elements.size() % 2 != 0) {
throw new IllegalArgumentException("number of elements must have even size");
}
}
@Override
public List<T> get(int index) {
return Arrays.asList(elements.get(index), elements.get(index + 1));
}
@Override
public int size() {
return elements.size() / 2;
}
}
然后我们可以定义我们需要的收集器。这本质上是collectingAndThen(toList(), PairList::new) 的简写:
/**
* Returns a collector that collects to a pair list.
*
* @return the collector
*/
public static <E> Collector<E, ?, PairList<E>> toPairList() {
return Collectors.collectingAndThen(Collectors.toList(), PairList::new);
}
请注意,对于我们知道支持列表是新生成的用例(如本例中),定义一个不会防御性地复制列表的 PairList 构造函数可能是值得的。不过,这现在并不是很重要。但是一旦我们这样做了,这个方法就是collectingAndThen(toCollection(ArrayList::new), PairList::newNonDefensivelyCopiedPairList)。
现在我们可以使用它了:
/**
* Creates a pair list with collectingAndThen, toList(), and PairList::new
*/
@Test
public void example() {
List<List<Integer>> intPairs = Stream.of(1, 2, 3, 4, 5, 6)
.collect(toPairList());
System.out.println(intPairs); // [[1, 2], [2, 3], [3, 4]]
List<List<String>> stringPairs = Stream.of("a", "b", "c", "d")
.collect(toPairList());
System.out.println(stringPairs); // [[a, b], [b, c]]
}
这是一个完整的源文件,其中包含一个可运行的示例(作为 JUnit 测试):
package ex;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
public class PairCollectors {
/**
* A view on a list of its elements as pairs.
*
* @param <T> the element type
*/
static class PairList<T> extends AbstractList<List<T>> {
private final List<T> elements;
/**
* Creates a new pair list.
*
* @param elements the elements
*
* @throws NullPointerException if elements is null
* @throws IllegalArgumentException if the length of elements is not even
*/
public PairList(List<T> elements) {
Objects.requireNonNull(elements, "elements must not be null");
this.elements = new ArrayList<>(elements);
if (this.elements.size() % 2 != 0) {
throw new IllegalArgumentException("number of elements must have even size");
}
}
@Override
public List<T> get(int index) {
return Arrays.asList(elements.get(index), elements.get(index + 1));
}
@Override
public int size() {
return elements.size() / 2;
}
}
/**
* Returns a collector that collects to a pair list.
*
* @return the collector
*/
public static <E> Collector<E, ?, PairList<E>> toPairList() {
return Collectors.collectingAndThen(Collectors.toList(), PairList::new);
}
/**
* Creates a pair list with collectingAndThen, toList(), and PairList::new
*/
@Test
public void example() {
List<List<Integer>> intPairs = Stream.of(1, 2, 3, 4, 5, 6)
.collect(toPairList());
System.out.println(intPairs); // [[1, 2], [2, 3], [3, 4]]
List<List<String>> stringPairs = Stream.of("a", "b", "c", "d")
.collect(toPairList());
System.out.println(stringPairs); // [[a, b], [b, c]]
}
}