Java 中间流操作是否可以在不破坏管道的情况下进行封装?

Java 中间流操作是否可以在不破坏管道的情况下进行封装?,java,java-8,java-stream,Java,Java 8,Java Stream,对于Java8流,是否可以以某种不会破坏流管道的方式封装和重用中间流操作 从以下方面考虑此示例: 假设我需要在代码中的不同位置使用filter和mapToInt操作。我可能希望尝试封装该逻辑,以便可以重用,例如: IntStream maleAges(Stream<Person> stream) { return stream .filter(p -> p.getGender() == Person.Sex.MALE) .mapToInt

对于Java8流,是否可以以某种不会破坏流管道的方式封装和重用中间流操作

从以下方面考虑此示例:

假设我需要在代码中的不同位置使用filter和mapToInt操作。我可能希望尝试封装该逻辑,以便可以重用,例如:

IntStream maleAges(Stream<Person> stream) {
    return stream
        .filter(p -> p.getGender() == Person.Sex.MALE)
        .mapToInt(Person::getAge)
}
Function<Stream<Person>, IntStream> agesForSex(Person.Sex sex) {
    return stream -> stream
        .filter(p -> p.getGender() == sex)
        .mapToInt(Person::getAge);
}

double averageBob = StreamEx.of(roster)
        .filter(p -> "Bob".equals(p.getName()))
        .chain(agesForSex(Person.Sex.MALE)) // Compiles!
        .average()
        .getAsDouble();
有更好的方法吗?我在想一些类似的事情:

double averageBob = roster
    .stream()
    .filter(p -> "Bob".equals(p.getName()))
    .apply(this::maleAges) // Doesn't compile
    .average()
    .getAsDouble();

一种方法是取而代之的是采用流,采用单个人并发出IntStream,例如:

 final Predicate<Person> isMale = p -> p.getGender() == Person.Sex.MALE;
 final Function<Person, IntStream> maleAges = person -> isMale.test(person)
            ? IntStream.of(person.age)
            : IntStream.empty();
 final double averageT = roster
                .stream()
                .flatMapToInt(maleAges)
                .average()
                .getAsDouble();
final谓词isMale=p->p.getGender()==Person.Sex.MALE;
最终功能maleAges=人->isMale.test(人)
? IntStream.of(人的年龄)
:IntStream.empty();
最终双平均值t=名册
.stream()
.flatMapToInt(maleAges)
.average()
.getAsDouble();
这样你就可以在任何地方重用你的maleAges功能

My library增强了标准流API和其他功能,它具有
chain
方法,该方法与您建议的
apply
完全相同:

double averageBob = StreamEx.of(roster)
        .filter(p -> "Bob".equals(p.getName()))
        .chain(this::maleAges) // Compiles!
        .average()
        .getAsDouble();
另一种可能的选择是从
maleAges
返回函数:

Function<Stream<Person>, IntStream> maleAges() {
    return stream -> stream
        .filter(p -> p.getGender() == Person.Sex.MALE)
        .mapToInt(Person::getAge);
}
通过这种方式,您可以轻松地参数化封装的操作。例如:

IntStream maleAges(Stream<Person> stream) {
    return stream
        .filter(p -> p.getGender() == Person.Sex.MALE)
        .mapToInt(Person::getAge)
}
Function<Stream<Person>, IntStream> agesForSex(Person.Sex sex) {
    return stream -> stream
        .filter(p -> p.getGender() == sex)
        .mapToInt(Person::getAge);
}

double averageBob = StreamEx.of(roster)
        .filter(p -> "Bob".equals(p.getName()))
        .chain(agesForSex(Person.Sex.MALE)) // Compiles!
        .average()
        .getAsDouble();
函数agesForSex(Person.Sex){
返回流->流
.filter(p->p.getGender()==sex)
.mapToInt(Person::getAge);
}
双平均值Bob=流x.of(花名册)
.filter(p->“Bob”.equals(p.getName()))
.chain(agesForSex(Person.Sex.MALE))//编译!
.average()
.getAsDouble();

int-maleAges(Person p){return p.getAge();}然后使用
.map(this::maleAges)
?@luigimendoza从本质上解释“年龄”,但不解释“男性”:),我正在寻找一种方法来封装不同类型的多个操作,并将它们插入管道,就像它们是单个操作一样。哦,对不起,然后是这样的:
return p.getGender()==Person.Sex.MALE?p、 getAge():0。在这种情况下,它将按预期工作。方法调用有什么问题?这是一个很好的解决方案,但唯一的缺点是流操作不能在封装的函数中使用。因此,虽然它在示例中运行良好,但在一般使用中可能有点太笨拙。我同意,当我编写它时,我觉得获取一个人并返回IntStream有点缺陷。有一个基于“Stream”返回“IntStream”的函数更“诗意”(因为我相信代码可以是真正的诗意),它感觉更自然、更自然。今天,我与同事讨论了这个问题,并向我解释说,一个名为Jool的库提供了与StreamEx大致相同的功能。我想我的答案最适合那些不想依赖外部依赖性并且想要纯Java8特性的人!我想这就是你指的?它看起来像是Tagir的StreamEx的可行替代品,感谢分享!非常好,这正是我所期望的:)
Function<Stream<Person>, IntStream> agesForSex(Person.Sex sex) {
    return stream -> stream
        .filter(p -> p.getGender() == sex)
        .mapToInt(Person::getAge);
}

double averageBob = StreamEx.of(roster)
        .filter(p -> "Bob".equals(p.getName()))
        .chain(agesForSex(Person.Sex.MALE)) // Compiles!
        .average()
        .getAsDouble();