找出Java 8流过滤器是否已过滤某些内容的优雅方法

时间:2016-01-29 09:06:20

标签: java java-8 java-stream

我从数据库中获取List Item

我做的事情如下:

List<Item> list;
list.stream()
    .filter( i -> i.condition() )
    .mapToLong( Item::asLong )
    .sum()
    ;

现在我想知道,如果过滤器已经过滤掉了某些内容,那么我可以从我的数据库中删除它,不再需要它。

我能做到:

List<Item> list2 = list.stream()
    .filter( i -> i.condition() )
    .collect( Collectors.toList() )
    ;

int theSizeIWant = list2.size();

list2.stream().mapToLong( Item::asLong )
     .sum()
     ;

但我想知道是否有一个更优雅的解决方案,不需要创建中间列表。

4 个答案:

答案 0 :(得分:4)

一种可能的解决方案是使用谓词对Stream进行分区并对值求和。使用partitioningBy(predicate, downstream)进行分区。在这种情况下,谓词将是您的过滤函数,下游收集器将summingLong来对值进行求和。

public static void main(String[] args) {
    List<Item> list = new ArrayList<>();
    Map<Boolean, Long> map = 
        list.stream()
            .collect(Collectors.partitioningBy(
                Item::condition, 
                Collectors.summingLong(Item::asLong)
            ));
    long sumWithTrueCondition = map.get(true);
    long sumWithFalseCondition = map.get(false);
}

地图将包含谓词true(分别为false)与true键(分别为false)的总和。

这样,如果某些内容已被过滤,sumWithTrueCondition将严格大于0.此外,您可以通过添加sumWithTrueConditionsumWithFalseCondition来获得总和。

答案 1 :(得分:3)

是的,你可以这样做。

Map<Boolean, List<Item>> partitions =
    list.stream.collect(Collectors.partitioningBy(i -> i.condition()));

partitions.get(true)会为您提供好的,partitions.get(false)会为您提供要删除的内容。

答案 2 :(得分:0)

另一个解决方案是计算lambda表达式中的坏元素:

List<String> strings = Arrays.asList("1", "2", "3", "12", "4", "5");
List<String> badOnes = new ArrayList<>();

strings.stream()
       .filter(s -> {
         boolean returnValue = !s.contains("1");
         if (!returnValue) {
           badOnes.add(s);
         }
         return returnValue;
       })
       .forEach(s -> System.out.println(s));

System.out.println(badOnes);

答案 3 :(得分:0)

这减轻了中间列表,但仍然需要进行第二次计算。如果某些事情没有通过这个条件,那么它就不会再向下流过,并且不会被计算在内。

int count = 0;

count必须是一个实例变量,然后你可以这样做:

List<Item> list;
list.stream()
    .filter( i -> i.condition() )
    .mapToLong( (item) -> { count++; return item.asLong(); } )
    .sum();

boolean isFiltered = list.size() > count;