在Java8Lambdas中,如何访问流中的原始对象?

在Java8Lambdas中,如何访问流中的原始对象?,lambda,java-8,java-stream,Lambda,Java 8,Java Stream,假设我有一个“a”的列表 List<A> as; 在lambda链中,我失去了对“a”的引用。有没有办法存储它并引用它或其他什么?我不知道您是否可以访问未修改的元素,但您可以通过以下方式修改操作链: as.stream() .filter(a -> a.getX() != null) .forEach(a -> a.setLookedUpVal(lookup.get(a.getX())) 现在我明白了,这会使问题变得更复杂,并且可能对解决现实世界的问题不感兴趣

假设我有一个“a”的列表

List<A> as;

在lambda链中,我失去了对“a”的引用。有没有办法存储它并引用它或其他什么?

我不知道您是否可以访问未修改的元素,但您可以通过以下方式修改操作链:

as.stream()
  .filter(a -> a.getX() != null)
  .forEach(a -> a.setLookedUpVal(lookup.get(a.getX()))
现在我明白了,这会使问题变得更复杂,并且可能对解决现实世界的问题不感兴趣。

但是,它的优点是始终与
流一起工作,这在某些情况下比在不同的步骤中使用不同的类型更简单、更可扩展。

如果您有更复杂的场景或出于某种原因不喜欢@Aaron answer,您可以执行flatMap捕获技巧,为每个外部元素创建一个元素流:

as.stream().
   flatMap(a -> Stream.of(a.getX()).
      filter(x -> x != null).
      map(x -> a)).
   forEach(System.out::println);
这里我们有嵌套的每个元素流,您可以在其中执行任何无状态流操作(
map
filter
peek
flatMap
),并引用原始元素。在原始元素变得不必要后,关闭
flatMap
,继续原始流。例如:

Stream.of("a", "bb", "ccc", "dd", "eeee")
    .flatMap(a -> Stream.of(a.length())
            .filter(x -> x > 2)
            .map(x -> a))
    .forEach(System.out::println);
// prints "ccc" and "eeee".
或两个过滤器:

Stream.of("a", "bb", "ccc", "dd", "eeee")
    .flatMap(a -> Stream.of(a.length())
            .filter(x -> x > 2)
            .map(x -> a.charAt(0)) // forget the length, now check the first symbol
            .filter(ch -> ch == 'c')
            .map(x -> a)) // forget the first symbol, reverting to the whole string
    .forEach(System.out::println);
// prints only "ccc"

当然,这些简单的场景可以像@Aaron建议的那样重写,但在更复杂的情况下,平面图捕获可能是合适的解决方案。

如果查找绑定到
x
,我建议更改代码以获得类似
a.lookup(lookup::get)
的内容。然后,您将为(a:as)if(a.getX()!=null)a.setLookedUpVal(lookup.get(a.getX()))使用一个简单的
forEach
或者,如果
getX()
很昂贵,那么对于(A:as){X X=A.getX();如果(X!=null)A.setLookedUpVal(lookup.get(X));}
。在决定使用之前,请将每个基于流的解决方案与之进行比较…或
.flatMap(a->a.length()>2&&a.charAt(0)='c'?Stream.of(a):null)
,这几乎与使用
过滤器一样简洁…
Stream.of("a", "bb", "ccc", "dd", "eeee")
    .flatMap(a -> Stream.of(a.length())
            .filter(x -> x > 2)
            .map(x -> a.charAt(0)) // forget the length, now check the first symbol
            .filter(ch -> ch == 'c')
            .map(x -> a)) // forget the first symbol, reverting to the whole string
    .forEach(System.out::println);
// prints only "ccc"