Java 8由多个谓词汇总

时间:2016-12-29 10:08:19

标签: java-8 java-stream

考虑使用Lombok注释

注释的以下pojo类
@Setter
@Getter
@Builder
@ToString
public class User {
    private String firstName;
    private String lastName;
    private Gender gender;
    private Integer age;
    private Integer points;
}

要求获得LongSummaryStatistics点数'跟随谓词的属性:

  1. Predicate<User> adultMenPredicate = user -> Gender.MALE == user.getGender && user.getAge()>18
  2. Predicate<User> adultWomenPredicate = user -> Gender.FEMALE == user.getGender && user.getAge()>18
  3. Predicate<User> minorPredicate = user -> user.getAge()<18
  4. 我目前的实施是:

    private LongSummaryStatistics getPointStats(List<User> users, Predicate<User> predicate) {
        return users.stream().filter(predicate).mapToLong(User::getPoints).summaryStatistics();
    }
    
    System.out.println("point stats for adult men: " + getPointStats(users, adultMenPredicate));
    System.out.println("point stats for adult women: " + getPointStats(users, adultWomenPredicate));
    System.out.println("point stats for minors: " + getPointStats(users, minorPredicate));
    

    这里我们迭代用户集合三次。是否有可能只在一次迭代中得到它?

1 个答案:

答案 0 :(得分:2)

我发现了类似的东西:

public static void main(String [] args) {
    List<User> users = ImmutableList.of(new User("a", "s", MALE, 19, 22),
                                        new User("a", "s", MALE, 15, 49),
                                        new User("a", "s", MALE, 22, 11),
                                        new User("a", "s", FEMALE, 19, 1),
                                        new User("a", "s", MALE, 12, 22));

    Map<Type, Integer> collect = users.stream()
            .map(u -> Tuple.tuple(u, resolveType(u)))
            .collect(Collectors.groupingBy(Tuple::right, Collectors.summingInt(t -> t.left().points)));
    System.out.println(collect);
}

public static Type resolveType(final User user) {
    if (user.gender == MALE && user.age > 18) {
        return Type.ADULT_MALE;
    } else if (user.gender == FEMALE && user.age > 18) {
        return Type.ADULT_FEMALE;
    } else {
        return Type.MINOR;
    }
}

public enum Type {
    ADULT_MALE, ADULT_FEMALE, MINOR
}

我想这是一个平衡的解决方案 - 非常有效和可读。 我不喜欢if-else语句,所以你可以用Map替换它:

private static final Map<Predicate<User>, Type> predicates = ImmutableMap.of(
        user -> user.getGender() == MALE && user.getAge() >= 18, Type.ADULT_MALE,
        user -> user.getGender() == FEMALE && user.getAge() >= 18, Type.ADULT_FEMALE,
        user -> user.getAge() < 18, Type.MINOR
);

public static Type resolveType(final User user) {
    return predicates.entrySet().stream()
            .filter(entry -> entry.getKey().test(user))
            .findFirst()
            .map(Map.Entry::getValue)
            .orElseThrow(RuntimeException::new);
}

打印:

{ADULT_MALE=33, MINOR=71, ADULT_FEMALE=1}

我猜你不必担心性能,除非你正在处理大量的收藏。

//编辑 只是为了说清楚。我的元组实现看起来像这样:

@ToString
@EqualsAndHashCode
public class Tuple<L, R> {
    public static <L, R> Tuple<L, R> tuple(L left, R right) {
        return new Tuple<>(left, right);
    }

    private final L left;
    private final R right;

    private Tuple(L left, R right) {
        this.left = left;
        this.right = right;
    }

    public L left() {
        return left;
    }

    public R right() {
        return right;
    }
}
相关问题