集合#删除JDK之间的不同行为

yfwxisqw  于 2021-07-12  发布在  Java
关注(0)|答案(1)|浏览(443)

Tomcat9.0.39在JDK11.0.10上运行。
或者在JDK1.8.0ď上运行Tomcat8.5.65。
以下代码使用JDK1.8.0ď编译,运行正常。

final Set<A> a = _a.stream().collect(Collectors.toSet());

a.removeIf(b -> 
    Objects.nonNull(b.getOne()) 
    && Objects.nonNull(b.getTwo()) 
    && Objects.nonNull(b.getThree())
    && Objects.nonNull(b.getFour())
);

然而 removeIf 部件不使用以下配置执行(下一个操作是在所有的 _a 列表):
tomcat 8.5.59在jdk 1.8.0_202-b08上运行。
Tomcat8.5.34在JDK1.8.0¿上运行。
为了达到预期的效果, removeIf 已被筛选器替换:

final Set<A> a = _a.stream()
    .filter(b -> 
        Objects.isNull(b.getOne()) 
        && Objects.isNull(b.getTwo()) 
        && Objects.isNull(b.getThree())
        && Objects.isNull(b.getFour())
    )       
    .collect(Collectors.toSet());

或与供应商:

final Set<A> a = _a.stream()
    .collect(Collectors.toCollection(TreeSet::new));

a.removeIf(b -> 
    Objects.nonNull(b.getOne()) 
    && Objects.nonNull(b.getTwo()) 
    && Objects.nonNull(b.getThree())
    && Objects.nonNull(b.getFour())
);

我读过关于收藏家#toset或收藏家#tolist的文章:
返回将输入元素累积到新集合/列表中的收集器。无法保证返回的集合/列表的类型、可变性、序列化或线程安全性;如果需要对返回的集合/列表进行更多控制,请使用tocollection(supplier)。
但在这里,如果没有并行流,则流是通过终端操作在最终集合中收集的,而collection#removeif是在JDK1.8中引入的。
所以我的问题是:
为什么它在不同的jdk次要版本上表现不同?
(或者至少在jdk<=1.8.0ď的情况下,它不能像预期的那样工作)
问/答
如果替换_a.stream().collect(collectors.toset());使用新哈希集<>(\u a)?
同样,在工作配置上工作,不在另一个上工作,打印不应该留在集合中的元素。

final Set<A> a = new HashSet<>(_a);

这种行为是“随机的”(如标题所示),意味着这种情况有时发生,但并不总是发生;或者仅仅是出乎意料,这意味着这种情况总是发生在特定的jdk版本上,但您只是不知道为什么?
这种情况总是发生在特定的jdk版本上,但我只是不知道为什么。1.8.0ď271之前 removeIf 从不执行(多次尝试确保),在此版本之后或使用此版本时,它总是过滤元素(也多次尝试)。
实现equals和hashcode是否正确?
a类正在实施 java.lang.Comparable<A> 这样地:

/*
 * (non-Javadoc)
 * @see java.lang.Object#equals(java.lang.Object)
 */
@Override
public boolean equals(Object o) {
    boolean result = false;
    if (o instanceof A) {
        A a = (A o;
        result = 
            getId1() == a.getId1()
            && getId2() == a.getId2()
            && getId3() == a.getId3();
    }
    return result;
}
/*
 * (non-Javadoc)
 * @see java.lang.Object#hashCode()
 */
@Override
public int hashCode() {
    StringBuilder sb = new StringBuilder();
    sb.append(getId1());
    sb.append(getId2());
    sb.append(getId3());
    return sb.hashCode();
}
/* 
 * (non-Javadoc)
 * @see java.lang.Comparable#compareTo(java.lang.Object)
 */
@Override
public int compareTo(A a) {
    return 
        getId1() == a.getId1() 
        && getId2() == a.getId2() 
        && getId3() == a.getId3() 
        ? 1 : 0;
}

如何确定代码尚未执行?
我使用的第一种方法是生产数据库中的表,它更新了所有元素,而只更新了缩减集的元素。这显示了错误。然后,第二种方法我曾经确定是一个简单的 printf 这样,在对更新表的数据库方法进行注解之后。

a.stream()
    .filter(b -> 
        Objects.nonNull(b.getOne()) 
        || Objects.nonNull(b.getTwo()) 
        || Objects.nonNull(b.getThree()) 
        || Objects.nonNull(b.getFour())
    )
    .forEach(a -> 
        System.out.printf(
            "%nbad elements remaining in the set : %s%n", 
            a.getId1()
        )
    );

打印出来的结果,在不起作用的配置(生产)上是多种多样的:有时更新了300项,有时更新了400项。在工作配置(开发)上,没有打印任何内容。这指出了它在jdk上的工作方式不同的事实。

2fjabf4q

2fjabf4q1#

筛选器和removeif predicate 在同一组条件上不匹配。

a.removeIf(b -> 
    Objects.nonNull(b.getOne()) 
    && Objects.nonNull(b.getTwo()) 
    && Objects.nonNull(b.getThree())
    && Objects.nonNull(b.getFour())
);

当你从 removeIf(nonNull && nonNull) 你需要什么 filter(isNull || isNull) 要匹配相同的值:

stream.filter(b -> 
    Objects.isNull(b.getOne()) 
    || Objects.isNull(b.getTwo()) 
    || Objects.isNull(b.getThree())
    || Objects.isNull(b.getFour())
)

您还可以将 predicate 赋给变量,而filter中使用的 predicate 是 Predicate.not :

Predicate<A> predicate = ...
a.removeIf(predicate) <=> stream.filter(Predicate.not(predicate));

相关问题