Any filter-like lambda operation which does not di

2019-01-18 17:32发布

问题:

I basically would like to do something like:

  assertEquals(Arrays.asList(1,2,3).stream()
                                   .noDiscardingFilter(x -> x!=1)
                                   .map(x -> x*10)
                                   .collect(Collectors.toList()),  
                Arrays.asList(1,20,30)
              )

This is an example, I don't need to get an answer on how to solve out that particular problem, it's just an example to show what's the fancy stuff I'm coming after.

回答1:

Any intermediate step affects the entire stream pipeline. There is no recognizable rule behind your wish that the noDiscardingFilter step affects what the subsequently chained map will do, but not the collect operation. If you want to have a conditional function, it would be much clearer to implement it as such:

public static <T> Function<T,T> conditional(
                                Predicate<? super T> p, Function<T, ? extends T> f) {
    return obj -> p.test(obj)? f.apply(obj): obj;
}

This can be used as

assertEquals(Stream.of(1, 2, 3)
        .map(conditional(x -> x!=1, x -> x*10))
        .collect(Collectors.toList()),
    Arrays.asList(1, 20, 30)
);

or

Stream.of(1, 5, null, 3, null, 4)
      .map(conditional(Objects::isNull, x -> 0)) // replacing null with default value
      .forEach(System.out::println);

or

Stream.of(1, 5, null, 3, null, 4)
      .map(conditional(Objects::nonNull, x -> x*10)) // null-safe calculation
      .forEach(System.out::println);

Note how in these use cases, it is immediately recognizable that the predicate and function passed to conditional belong to the same scope, which is different from the chained stream operations.



回答2:

If you want to only change the entries which match the filter but retain the rest.

assertEquals(Arrays.asList(-1, 1, 20, 30),
             Stream.of(-1, 1, 2, 3)
                   .map(i -> i <= 1 ? i /* retain */ : 10 * i /* transform */)
                   .collect(Collectors.toList()));