From 2f23075ac24ea51864feb021a690c825d4fc14ad Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 15 Aug 2023 09:47:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DFieldsComparator=E6=AF=94?= =?UTF-8?q?=E8=BE=83=E7=BB=93=E6=9E=9C=E4=B8=8D=E6=AD=A3=E7=A1=AE=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +- .../core/comparator/FieldComparator.java | 12 ++-- .../core/comparator/FieldsComparator.java | 3 +- .../core/comparator/FuncComparator.java | 21 ++++++- .../hutool/core/comparator/Issue3259Test.java | 56 +++++++++++++++++++ 5 files changed, 85 insertions(+), 10 deletions(-) create mode 100755 hutool-core/src/test/java/cn/hutool/core/comparator/Issue3259Test.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 0182d0b84..b951f4175 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ # 🚀Changelog ------------------------------------------------------------------------------------------------------------- -# 5.8.22(2023-08-13) +# 5.8.22(2023-08-15) ### 🐣新特性 * 【core 】 NumberUtil.nullToZero增加重载(issue#I7PPD2@Gitee) @@ -18,6 +18,7 @@ * 【db 】 修复SqlUtil.formatSql 格式化的sql换行异常(pr#3247@Github) * 【core 】 修复DateUtil.parse 给定一个时间解析错误问题(issue#I7QI6R@Gitee) * 【core 】 去除默认的ACCEPT_LANGUAGE(issue#3258@Github) +* 【core 】 修复FieldsComparator比较结果不正确问题(issue#3259@Github) ------------------------------------------------------------------------------------------------------------- # 5.8.21(2023-07-29) diff --git a/hutool-core/src/main/java/cn/hutool/core/comparator/FieldComparator.java b/hutool-core/src/main/java/cn/hutool/core/comparator/FieldComparator.java index b4a1dd19a..482b1466e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/comparator/FieldComparator.java +++ b/hutool-core/src/main/java/cn/hutool/core/comparator/FieldComparator.java @@ -33,19 +33,21 @@ public class FieldComparator extends FuncComparator { * @param field 字段 */ public FieldComparator(Field field) { - this(true, field); + this(true, true, field); } /** * 构造 * * @param nullGreater 是否{@code null}在后 + * @param compareSelf 在字段值相同情况下,是否比较对象本身。 + * 如果此项为{@code false},字段值比较后为0会导致对象被认为相同,可能导致被去重。 * @param field 字段 */ - public FieldComparator(boolean nullGreater, Field field) { - super(nullGreater, (bean) -> - (Comparable) ReflectUtil.getFieldValue(bean, - Assert.notNull(field, "Field must be not null!"))); + public FieldComparator(boolean nullGreater, boolean compareSelf, Field field) { + super(nullGreater, compareSelf, (bean) -> + (Comparable) ReflectUtil.getFieldValue(bean, + Assert.notNull(field, "Field must be not null!"))); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/comparator/FieldsComparator.java b/hutool-core/src/main/java/cn/hutool/core/comparator/FieldsComparator.java index 5c10eda78..539e6b5d7 100644 --- a/hutool-core/src/main/java/cn/hutool/core/comparator/FieldsComparator.java +++ b/hutool-core/src/main/java/cn/hutool/core/comparator/FieldsComparator.java @@ -38,7 +38,8 @@ public class FieldsComparator extends NullComparator { for (String fieldName : fieldNames) { field = ClassUtil.getDeclaredField(beanClass, fieldName); Assert.notNull(field, "Field [{}] not found in Class [{}]", fieldName, beanClass.getName()); - final int compare = new FieldComparator<>(field).compare(a, b); + // issue#3259,多个字段比较时,允许字段值重复 + final int compare = new FieldComparator<>(true, false, field).compare(a, b); if (0 != compare) { return compare; } diff --git a/hutool-core/src/main/java/cn/hutool/core/comparator/FuncComparator.java b/hutool-core/src/main/java/cn/hutool/core/comparator/FuncComparator.java index ea32bba95..6672c0ade 100644 --- a/hutool-core/src/main/java/cn/hutool/core/comparator/FuncComparator.java +++ b/hutool-core/src/main/java/cn/hutool/core/comparator/FuncComparator.java @@ -13,16 +13,31 @@ import java.util.function.Function; public class FuncComparator extends NullComparator { private static final long serialVersionUID = 1L; + private final boolean compareSelf; private final Function> func; /** * 构造 * * @param nullGreater 是否{@code null}在后 - * @param func 比较项获取函数 + * @param func 比较项获取函数,此函数根据传入的一个对象,生成对应的可比较对象,然后根据这个返回值比较 */ public FuncComparator(boolean nullGreater, Function> func) { + this(nullGreater, true, func); + } + + /** + * 构造 + * + * @param nullGreater 是否{@code null}在后 + * @param compareSelf 在字段值相同情况下,是否比较对象本身。 + * 如果此项为{@code false},字段值比较后为0会导致对象被认为相同,可能导致被去重。 + * @param func 比较项获取函数,此函数根据传入的一个对象,生成对应的可比较对象,然后根据这个返回值比较 + * @since 5.8.22 + */ + public FuncComparator(boolean nullGreater, boolean compareSelf, Function> func) { super(nullGreater, null); + this.compareSelf = compareSelf; this.func = func; } @@ -43,7 +58,7 @@ public class FuncComparator extends NullComparator { /** * 对象及对应比较的值的综合比较
* 考虑到如果对象对应的比较值相同,如对象的字段值相同,则返回相同结果,此时在TreeMap等容器比较去重时会去重。
- * 因此需要比较下对象本身以避免去重 + * 因此当{@link #compareSelf}为{@code true}时需要比较下对象本身以避免去重 * * @param o1 对象1 * @param o2 对象2 @@ -54,7 +69,7 @@ public class FuncComparator extends NullComparator { @SuppressWarnings({"rawtypes", "unchecked"}) private int compare(T o1, T o2, Comparable v1, Comparable v2) { int result = ObjectUtil.compare(v1, v2, this.nullGreater); - if (0 == result) { + if (compareSelf && 0 == result) { //避免TreeSet / TreeMap 过滤掉排序字段相同但是对象不相同的情况 result = CompareUtil.compare(o1, o2, this.nullGreater); } diff --git a/hutool-core/src/test/java/cn/hutool/core/comparator/Issue3259Test.java b/hutool-core/src/test/java/cn/hutool/core/comparator/Issue3259Test.java new file mode 100755 index 000000000..6301d056b --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/comparator/Issue3259Test.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package cn.hutool.core.comparator; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.RandomUtil; +import lombok.AllArgsConstructor; +import lombok.ToString; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +public class Issue3259Test { + + @Test + public void fieldsComparatorTest() { + Model x = new Model(1, 1); + Model y = new Model(1, RandomUtil.randomInt(2, 100)); + + Assert.assertTrue(new FieldsComparator<>(Model.class, "a", "b").compare(x, y) < 0); + } + + @Test + @Ignore + public void sortTest() { + for(int i = 2; i < 5; i++) { + Model x = new Model(1, 1); + Model y = new Model(1, i); + + List all = ListUtil.of(x, y); + all = CollUtil.sort(new ArrayList<>(all), new FieldsComparator<>(Model.class, "a", "b")); + System.out.println(all); + } + } + + @AllArgsConstructor + @ToString + public static class Model { + public int a; + public int b; + } +}