2016-09-11 85 views
3

我怎样才能重用java8(也许是一个memoization过程)值已通过流迭代计算?Java8流与记忆

如果流被复制或再次提供,它将被重新计算。在某些情况下,最好为该CPU时间交易内存。从一开始收集所有内容可能不是一个好主意,因为该流用于查找满足谓词的第一个项目。

Stream<Integer> all = Stream.of(1,2,3,4,5, ...<many other values>...). 
     map(x->veryLongTimeToComputeFunction(x)); 
System.out.println("fast find of 2"+all.filter(x->x>1).findFirst()); 

//both of these two lines generate a "java.lang.IllegalStateException: stream has already been operated upon or closed" 
System.out.println("no find"+all.filter(x->x>10).findFirst()); 
System.out.println("find again"+all.filter(x->x>4).findFirst()); 

的问题是呈三角Copy a stream to avoid "stream has already been operated upon or closed" (java 8)

回答

0

我建议的列表中的流收集您的Stream到列表中,然后运行您的过滤器。

+0

但是,这将执行veryLongTimeToComputeFunction所有字段只是在最后保持第一个。 – raisercostin

1

为什么不在veryLongTimeToComputeFunction里面使用memoization?你可以把备忘录缓存作为一个参数给func。

0

规范的内存中的流源是一个集合。一个简单但不能并行的流式记录可以实现如下:

public static void main(String[] args) { 
    Supplier<Stream<Integer>> s=memoize(
     IntStream.range(0, 10_000) 
       .map(x -> veryLongTimeToComputeFunction(x)) 
    ); 
    System.out.println("First item > 1 "+s.get().filter(x -> x>1).findFirst()); 
    System.out.println("First item > 10 "+s.get().filter(x -> x>10).findFirst()); 
    System.out.println("First item > 4 "+s.get().filter(x -> x>4).findFirst()); 
} 
static int veryLongTimeToComputeFunction(int arg) { 
    System.out.println("veryLongTimeToComputeFunction("+arg+")"); 
    return arg; 
} 

public static <T> Supplier<Stream<T>> memoize(BaseStream<T,?> stream) { 
    Spliterator<T> sp=stream.spliterator(); 
    class S extends Spliterators.AbstractSpliterator<T> { 
     ArrayList<T> mem=new ArrayList<>(); 
     S() { super(sp.estimateSize(), sp.characteristics()); } 
     public boolean tryAdvance(Consumer<? super T> action) { 
      int ix=mem.size(); 
      if(sp.tryAdvance(mem::add)) { 
       action.accept(mem.get(ix)); 
       return true; 
      } 
      return false; 
     } 
    } 
    S s=new S(); 
    return() -> Stream.concat(s.mem.stream(), StreamSupport.stream(s, false)); 
} 

在向供应商请求下一个流之前,请务必完成流处理。

+0

谢谢。我会尝试一下我希望能够在java集合中找到一些东西,或者至少在番石榴,apache共享或其他一般可用的小型库中找到。 – raisercostin

+0

那么,你可以把它放到一个小型的库中...... – Holger

0

流并不意味着已保存,他们即将流程数据。

例如:您正在观看DVD,用java术语说,dvd就像一个集合,从您的dvd播放器传输到您的电视的数据是一个流。你不能保存流,但是你可以用java来刻录CD。

还有其他的选择:

  • 提取/重构你的流操作或谓词是得到一个流作为参数,并返回一个流
  • 使用缓存框架的方法:例如,在Spring方法可以用@Cacheable注释。第一次调用执行方法,后续调用读取缓存中的结果定义的时间
  • ,如果你正在寻找你长期运行的任务无阻塞执行,看看RxJava
+0

如果java流不能被保存,那么这个集合是做什么的?斯卡拉流正在这样做,而不需要专门的框架。 – raisercostin

+0

@raisercostin是关于流的java方法。在Java流中只是一个功能性的“附加”,Scala被设计为纯粹的功能。无论如何,因为veryLongTimeToComputeFunction(x)在cpu上非常沉重,您可以通过在流中添加“.parallel()”来获得很多性能。 – Journeycorner

0

的Java 8流本质上是懒惰的。在流上执行的操作按垂直顺序进行评估。 要达到可以使用下面的代码来实现什么:

Stream.of(1,2,3,4,5, ...<many other values>...) 
    .map(x-> veryLongTimeToComputeFunction(x)) 
    .filter(x-> x > 1) 
    .findFirst(); 

这将确保该veryLongTimeToComputeFunction()只能做到匹配的第一个元素没有找到被调用。之后,操作将终止。 在最坏的情况下,如果最后一个数字是符合条件的数字,则会调用所有数字的VeryLongTimeToComputeFunction。

此外,您可以将并行流与findAny()方法结合使用。它会加快性能。