Java8流上的缓冲区操作符

Java8流上的缓冲区操作符,java,java-8,functional-programming,rx-java,java-stream,Java,Java 8,Functional Programming,Rx Java,Java Stream,我正在尝试编写一个Java8流收集器,它反映了 我对此有一个工作代码: // This will gather numbers 1 to 13 and combine them in groups of // three while preserving the order even if its a parallel stream. final List<List<String>> triads = IntStream.range(1, 14) .par

我正在尝试编写一个Java8流收集器,它反映了

我对此有一个工作代码:

// This will gather numbers 1 to 13 and combine them in groups of
// three while preserving the order even if its a parallel stream.
final List<List<String>> triads = IntStream.range(1, 14)
        .parallel()
        .boxed()
        .map(Object::toString)
        .collect(ArrayList::new, accumulator, combiner);

System.out.println(triads.toString())
在这篇文章中,我可能已经彻底扼杀了流的概念,但是有没有一种方法可以简化、优化或重写它呢

为了简单起见,下面是完整的程序(遗憾的是,stackoverflow不允许在没有足够描述的情况下发布代码)


以下是我的想法1:


1我最初打算让它返回一个流,但我意识到,由于流的惰性,使用流迭代器会使此任务变得比需要的更困难。

以下是我的想法1:


1我最初打算让它返回一个流,但我意识到,由于流的惰性,使用流迭代器会使这项任务变得更加困难。

首先,要将其捆绑到一个类中,您可以将其实现为一个
收集器
,因此您基本上希望将元素分组成块?如果是这样的话,这已经被问了好几年了times@Eugene你介意分享一个吗?这里有一个这样的线程:。如果流是有序的,最简单的解决方案可能就是将其转换为ArrayList,使用Guava并从中生成另一个流。对于初学者来说,要将其捆绑到单个类中,您可以将其实现为
收集器
,所以您基本上想将元素分组?如果是这样的话,这已经被问了好几年了times@Eugene你介意分享一个吗?这里有一个这样的线程:。如果流是有序的,最简单的解决方案可能就是将其转换为ArrayList,使用Guava并从中生成另一个流。
final BiConsumer<List<List<String>>, String> accumulator = (acc, a) -> {
      StringBuilder stringBuilder = new StringBuilder();
      stringBuilder.append("Accumulator|");
      stringBuilder.append("Before: ").append(acc.toString());
      int accumulatorSize = acc.size();
      if (accumulatorSize == 0) {
        List<String> newList = new ArrayList<>();
        newList.add(a);
        acc.add(newList);
      } else {
        List<String> lastList = acc.get(accumulatorSize - 1);
        if (lastList.size() != 3) {
          lastList.add(a);
        } else {
          List<String> newList = new ArrayList<>();
          newList.add(a);
          acc.add(newList);
        }
      }
      stringBuilder.append("|After: ").append(acc.toString());
      stringBuilder.append("|a: ").append(a);
      System.out.println(stringBuilder.toString());
    };
// Utility method to make first list of size 3 
// by shifting elements from second to first list
final BiConsumer<List<String>, List<String>> fixSize = (l1, l2) -> {
  while(l1.size() != 3 && l2.size() > 0) {
    l1.add(l2.remove(0));
  }
};

final BiConsumer<List<List<String>>, List<List<String>>> combiner = (l1, l2) -> {
  StringBuilder stringBuilder = new StringBuilder();
  stringBuilder.append("Combiner|");
  stringBuilder.append("Before, l1: ").append(l1).append(", l2: ").append(l2);
  if (l1.isEmpty()) {
    // l1 is empty
    l1.addAll(l2);
  } else {
    // l1 is not empty
    List<String> lastL1List = l1.get(l1.size() - 1);
    if (lastL1List.size() == 3) {
      l1.addAll(l2);
    } else {
      if (l2.isEmpty()) {
        // do nothing
      } else {
        List<List<String>> fixSizeList = new ArrayList<>(1 + l2.size());
        fixSizeList.add(lastL1List);
        fixSizeList.addAll(l2);
        for (int i = 0; i < fixSizeList.size() - 1; i++) {
          List<String> x = fixSizeList.get(i), y = fixSizeList.get(i + 1);
          fixSize.accept(x, y);
        }
        l2.stream().filter(l -> !l.isEmpty()).forEach(l1::add);
        // everything is now of size three except, may be last
      }
    }
  }
  stringBuilder.append("|After, l1: ").append(l1).append(", l2: ").append(l2);
  System.out.println(stringBuilder.toString());
};
Accumulator|Before: []|After: [[12]]|a: 12
Accumulator|Before: []|After: [[2]]|a: 2
Accumulator|Before: []|After: [[11]]|a: 11
Accumulator|Before: []|After: [[6]]|a: 6
Accumulator|Before: []|After: [[4]]|a: 4
Accumulator|Before: []|After: [[1]]|a: 1
Accumulator|Before: []|After: [[13]]|a: 13
Accumulator|Before: []|After: [[8]]|a: 8
Accumulator|Before: []|After: [[3]]|a: 3
Accumulator|Before: []|After: [[5]]|a: 5
Accumulator|Before: []|After: [[10]]|a: 10
Accumulator|Before: []|After: [[7]]|a: 7
Accumulator|Before: []|After: [[9]]|a: 9
Combiner|Before, l1: [[5]], l2: [[6]]|After, l1: [[5, 6]], l2: [[]]
Combiner|Before, l1: [[12]], l2: [[13]]|After, l1: [[12, 13]], l2: [[]]
Combiner|Before, l1: [[2]], l2: [[3]]|After, l1: [[2, 3]], l2: [[]]
Combiner|Before, l1: [[8]], l2: [[9]]|After, l1: [[8, 9]], l2: [[]]
Combiner|Before, l1: [[10]], l2: [[11]]|After, l1: [[10, 11]], l2: [[]]
Combiner|Before, l1: [[4]], l2: [[5, 6]]|After, l1: [[4, 5, 6]], l2: [[]]
Combiner|Before, l1: [[1]], l2: [[2, 3]]|After, l1: [[1, 2, 3]], l2: [[]]
Combiner|Before, l1: [[7]], l2: [[8, 9]]|After, l1: [[7, 8, 9]], l2: [[]]
Combiner|Before, l1: [[10, 11]], l2: [[12, 13]]|After, l1: [[10, 11, 12], [13]], l2: [[13]]
Combiner|Before, l1: [[1, 2, 3]], l2: [[4, 5, 6]]|After, l1: [[1, 2, 3], [4, 5, 6]], l2: [[4, 5, 6]]
Combiner|Before, l1: [[7, 8, 9]], l2: [[10, 11, 12], [13]]|After, l1: [[7, 8, 9], [10, 11, 12], [13]], l2: [[10, 11, 12], [13]]
Combiner|Before, l1: [[1, 2, 3], [4, 5, 6]], l2: [[7, 8, 9], [10, 11, 12], [13]]|After, l1: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13]], l2: [[7, 8, 9], [10, 11, 12], [13]]
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13]]
public static <T> Stream<List<T>> buffer(Stream<T> stream, final long count) {
    final Iterator<T> streamIterator = stream.iterator();

    return StreamSupport.stream(Spliterators.spliteratorUnknownSize(new Iterator<List<T>>() {
        @Override
        public boolean hasNext() {
            return streamIterator.hasNext();
        }

        @Override
        public List<T>next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            List<T> intermediate = new ArrayList<>();
            for (long v = 0; v < count && hasNext(); v++) {
                intermediate.add(streamIterator.next());
            }
            return intermediate;
        }
    }, 0), false);
}
public class Test {
    public static void main(String[] args) {
        List<List<Integer>> triads = buffer(IntStream.range(1, 14)
                                                    .boxed()
                                                    .parallel(), 3).collect(Collectors.toList());

        System.out.println(triads);
        System.out.println("Empty stream test");
        System.out.println(buffer(Stream.<Integer>empty(), 4).collect(Collectors.toList()));

        System.out.println("Intermediate size greater than stream size");
        System.out.println(buffer(IntStream.range(1, 14)
                                          .boxed()
                                          .parallel(), 15).collect(Collectors.toList()));

        System.out.println("Intermediate size same as stream size");
        System.out.println(buffer(IntStream.range(1, 14)
                                          .boxed()
                                          .parallel(), 14).collect(Collectors.toList()));

        System.out.println("Intermediate size is a multiple of stream size");
        System.out.println(buffer(IntStream.range(0, 14)
                                          .boxed()
                                          .parallel(), 7).collect(Collectors.toList()));
    }
/tmp 
➜ javac Test.java

/tmp 
➜ java Test      
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13]]
Empty stream test
[]
Intermediate size greater than stream size
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]]
Intermediate size same as stream size
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]]
Intermediate size is a multiple of stream size
[[0, 1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13]]