Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 8流:多过滤器与复杂条件_Java_Lambda_Filter_Java 8_Java Stream - Fatal编程技术网

Java 8流:多过滤器与复杂条件

Java 8流:多过滤器与复杂条件,java,lambda,filter,java-8,java-stream,Java,Lambda,Filter,Java 8,Java Stream,有时,您希望过滤具有多个条件的流: myList.stream().filter(x -> x.size() > 10).filter(x -> x.isCool()) ... 或者,您也可以对复杂条件和单个过滤器执行相同操作: myList.stream().filter(x -> x.size() > 10 && x -> x.isCool()) ... 我猜第二种方法有更好的性能特征,但我不知道 第一种方法在可读性方面占优势,但什么对

有时,您希望过滤具有多个条件的

myList.stream().filter(x -> x.size() > 10).filter(x -> x.isCool()) ...
或者,您也可以对复杂条件和单个
过滤器执行相同操作:

myList.stream().filter(x -> x.size() > 10 && x -> x.isCool()) ...
我猜第二种方法有更好的性能特征,但我不知道


第一种方法在可读性方面占优势,但什么对性能更有利呢?

两种方法必须执行的代码非常相似,以至于您无法可靠地预测结果。底层对象结构可能有所不同,但这对热点优化器来说并不是什么挑战。因此,这取决于其他环境条件,如果存在任何差异,这些条件将导致更快的执行

组合两个筛选器实例将创建更多的对象,从而创建更多的委派代码,但如果使用方法引用而不是lambda表达式,则这可能会发生变化,例如,使用
筛选器(x->x.isCool())
替换
过滤器(ItemType::isCool)
。这样就消除了为lambda表达式创建的合成委托方法。因此,使用两个方法引用组合两个筛选器可能会创建与使用带有
&&
的lambda表达式的单个
筛选器调用相同或更少的委派代码

但是,如上所述,这种开销将被热点优化器消除,可以忽略不计

理论上,两个过滤器可能比单个过滤器更容易并行,但这仅适用于计算量较大的任务

因此,没有简单的答案

底线是,不要考虑低于气味检测阈值的性能差异。使用更具可读性的内容



CharStyle…并且需要一个执行后续阶段并行处理的实现,这是标准流实现目前没有走的路。此测试表明,您的第二个选项可以执行得更好。首先是调查结果,然后是代码:

one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=4142, min=29, average=41.420000, max=82}
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=13315, min=117, average=133.150000, max=153}
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=10320, min=82, average=103.200000, max=127}
enum Gender {
    FEMALE,
    MALE
}

static class User {
    Gender gender;
    int age;

    public User(Gender gender, int age){
        this.gender = gender;
        this.age = age;
    }

    public Gender getGender() {
        return gender;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

static long test1(List<User> users){
    long time1 = System.currentTimeMillis();
    users.stream()
            .filter((u) -> u.getGender() == Gender.FEMALE && u.getAge() % 2 == 0)
            .allMatch(u -> true);                   // least overhead terminal function I can think of
    long time2 = System.currentTimeMillis();
    return time2 - time1;
}

static long test2(List<User> users){
    long time1 = System.currentTimeMillis();
    users.stream()
            .filter(u -> u.getGender() == Gender.FEMALE)
            .filter(u -> u.getAge() % 2 == 0)
            .allMatch(u -> true);                   // least overhead terminal function I can think of
    long time2 = System.currentTimeMillis();
    return time2 - time1;
}

static long test3(List<User> users){
    long time1 = System.currentTimeMillis();
    users.stream()
            .filter(((Predicate<User>) u -> u.getGender() == Gender.FEMALE).and(u -> u.getAge() % 2 == 0))
            .allMatch(u -> true);                   // least overhead terminal function I can think of
    long time2 = System.currentTimeMillis();
    return time2 - time1;
}

public static void main(String... args) {
    int size = 10000000;
    List<User> users =
    IntStream.range(0,size)
            .mapToObj(i -> i % 2 == 0 ? new User(Gender.MALE, i % 100) : new User(Gender.FEMALE, i % 100))
            .collect(Collectors.toCollection(()->new ArrayList<>(size)));
    repeat("one filter with predicate of form u -> exp1 && exp2", users, Temp::test1, 100);
    repeat("two filters with predicates of form u -> exp1", users, Temp::test2, 100);
    repeat("one filter with predicate of form predOne.and(pred2)", users, Temp::test3, 100);
}

private static void repeat(String name, List<User> users, ToLongFunction<List<User>> test, int iterations) {
    System.out.println(name + ", list size " + users.size() + ", averaged over " + iterations + " runs: " + IntStream.range(0, iterations)
            .mapToLong(i -> test.applyAsLong(users))
            .summaryStatistics());
}
现在代码是:

one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=4142, min=29, average=41.420000, max=82}
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=13315, min=117, average=133.150000, max=153}
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=10320, min=82, average=103.200000, max=127}
enum Gender {
    FEMALE,
    MALE
}

static class User {
    Gender gender;
    int age;

    public User(Gender gender, int age){
        this.gender = gender;
        this.age = age;
    }

    public Gender getGender() {
        return gender;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

static long test1(List<User> users){
    long time1 = System.currentTimeMillis();
    users.stream()
            .filter((u) -> u.getGender() == Gender.FEMALE && u.getAge() % 2 == 0)
            .allMatch(u -> true);                   // least overhead terminal function I can think of
    long time2 = System.currentTimeMillis();
    return time2 - time1;
}

static long test2(List<User> users){
    long time1 = System.currentTimeMillis();
    users.stream()
            .filter(u -> u.getGender() == Gender.FEMALE)
            .filter(u -> u.getAge() % 2 == 0)
            .allMatch(u -> true);                   // least overhead terminal function I can think of
    long time2 = System.currentTimeMillis();
    return time2 - time1;
}

static long test3(List<User> users){
    long time1 = System.currentTimeMillis();
    users.stream()
            .filter(((Predicate<User>) u -> u.getGender() == Gender.FEMALE).and(u -> u.getAge() % 2 == 0))
            .allMatch(u -> true);                   // least overhead terminal function I can think of
    long time2 = System.currentTimeMillis();
    return time2 - time1;
}

public static void main(String... args) {
    int size = 10000000;
    List<User> users =
    IntStream.range(0,size)
            .mapToObj(i -> i % 2 == 0 ? new User(Gender.MALE, i % 100) : new User(Gender.FEMALE, i % 100))
            .collect(Collectors.toCollection(()->new ArrayList<>(size)));
    repeat("one filter with predicate of form u -> exp1 && exp2", users, Temp::test1, 100);
    repeat("two filters with predicates of form u -> exp1", users, Temp::test2, 100);
    repeat("one filter with predicate of form predOne.and(pred2)", users, Temp::test3, 100);
}

private static void repeat(String name, List<User> users, ToLongFunction<List<User>> test, int iterations) {
    System.out.println(name + ", list size " + users.size() + ", averaged over " + iterations + " runs: " + IntStream.range(0, iterations)
            .mapToLong(i -> test.applyAsLong(users))
            .summaryStatistics());
}
enum性别{
女,,
男性
}
静态类用户{
性别;
智力年龄;
公共用户(性别、年龄){
这个。性别=性别;
这个。年龄=年龄;
}
公共性别{
返回性别;
}
公共性别(性别){
这个。性别=性别;
}
公共整数getAge(){
回归年龄;
}
公共无效设置(整数){
这个。年龄=年龄;
}
}
静态长测试1(列出用户){
长时间1=System.currentTimeMillis();
users.stream()
.filter((u)->u.getGender()==Gender.FEMALE&&u.getAge()%2==0)
.allMatch(u->true);//我能想到的开销最小的终端函数
长时间2=System.currentTimeMillis();
返回时间2-时间1;
}
静态长测试2(列出用户){
长时间1=System.currentTimeMillis();
users.stream()
.filter(u->u.getGender()==Gender.FEMALE)
.filter(u->u.getAge()%2==0)
.allMatch(u->true);//我能想到的开销最小的终端函数
长时间2=System.currentTimeMillis();
返回时间2-时间1;
}
静态长测试3(列出用户){
长时间1=System.currentTimeMillis();
users.stream()
.filter(((谓词)u->u.getGender()==Gender.FEMALE)和(u->u.getAge()%2==0))
.allMatch(u->true);//我能想到的开销最小的终端函数
长时间2=System.currentTimeMillis();
返回时间2-时间1;
}
公共静态void main(字符串…参数){
int size=10000000;
列出用户=
IntStream.range(0,大小)
.mapToObj(i->i%2==0?新用户(Gender.MALE,i%100):新用户(Gender.MALE,i%100))
.collect(收集器.toCollection(()->新阵列列表(大小));
重复(“一个过滤器,其谓词形式为u->exp1&&exp2”,用户,Temp::test1100);
重复(“两个过滤器,其谓词形式为u->exp1”,用户,Temp::test2100);
重复(“一个带有predOne.and(pred2)形式谓词的过滤器”,用户,Temp::test3100);
}
私有静态void repeat(字符串名、列表用户、tolong函数测试、int迭代){
System.out.println(name+”,列表大小“+users.size()+”,在“+iterations+”运行期间的平均值:“+IntStream.range(0,iterations)
.mapToLong(i->test.applyAsLong(用户))
.summaryStatistics());
}

这是@Hank D共享的6种不同样本测试组合的结果 显然,
u->exp1&&exp2形式的谓词在所有情况下都是高效的

one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=3372, min=31, average=33.720000, max=47}
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=9150, min=85, average=91.500000, max=118}
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=9046, min=81, average=90.460000, max=150}

one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=8336, min=77, average=83.360000, max=189}
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=9094, min=84, average=90.940000, max=176}
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=10501, min=99, average=105.010000, max=136}

two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=11117, min=98, average=111.170000, max=238}
one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=8346, min=77, average=83.460000, max=113}
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=9089, min=81, average=90.890000, max=137}

two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=10434, min=98, average=104.340000, max=132}
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=9113, min=81, average=91.130000, max=179}
one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=8258, min=77, average=82.580000, max=100}

one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=9131, min=81, average=91.310000, max=139}
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=10265, min=97, average=102.650000, max=131}
one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=8442, min=77, average=84.420000, max=156}

one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=8553, min=81, average=85.530000, max=125}
one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=8219, min=77, average=82.190000, max=142}
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=10305, min=97, average=103.050000, max=132}

从性能的角度来看,复杂的过滤条件更好,但最好的性能将显示出循环的旧式,标准的
if子句是最好的选项。小阵列上的差异10个元素的差异可能约为2倍,而大阵列上的差异并不大。
您可以看看我的,在那里我对多个阵列迭代选项进行了性能测试

对于小型阵列10个单元吞吐量ops/s: 对于中等10000个元件的吞吐量ops/s: 对于大型阵列1000000个元素吞吐量ops/s:

注意:测试在上运行

  • 8 CPU
  • 1GB内存
  • 操作系统版本:16.04.1 LTS(Xenial Xerus)
  • java版本:1.8.0_121
  • jvm:-XX:+UseG1GC-server-Xmx1024m-Xms1024m
更新: Java11在性能上取得了一些进步,但动态性保持不变

基准模式:吞吐量,操作/时间

在这种情况下,编写可读性更强的代码。性能差异是最小的(并且是高度情境性的)。忘记纳米优化,使用可读性和可维护性很高的代码。对于流,应该始终单独使用每个操作,包括过滤器。代码不需要在每个过滤器之后迭代生成的流吗?@Juan Carlos Diaz:不,流不需要