diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/comparator/FieldComparator.java b/hutool-core/src/main/java/org/dromara/hutool/core/comparator/FieldComparator.java index 33f840d8f..6e68cff2f 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/comparator/FieldComparator.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/comparator/FieldComparator.java @@ -44,19 +44,22 @@ public class FieldComparator extends FuncComparator { * @param field 字段 */ public FieldComparator(final Field field) { - this(true, field); + this(true, true, field); } + /** * 构造 * * @param nullGreater 是否{@code null}在后 + * @param compareSelf 在字段值相同情况下,是否比较对象本身。 + * 如果此项为{@code false},字段值比较后为0会导致对象被认为相同,可能导致被去重。 * @param field 字段 */ - public FieldComparator(final boolean nullGreater, final Field field) { - super(nullGreater, (bean) -> - (Comparable) FieldUtil.getFieldValue(bean, - Assert.notNull(field, "Field must be not null!"))); + public FieldComparator(final boolean nullGreater, final boolean compareSelf, final Field field) { + super(nullGreater, compareSelf, (bean) -> + (Comparable) FieldUtil.getFieldValue(bean, + Assert.notNull(field, "Field must be not null!"))); } /** diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/comparator/FieldsComparator.java b/hutool-core/src/main/java/org/dromara/hutool/core/comparator/FieldsComparator.java index 25d2c01c0..607844c44 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/comparator/FieldsComparator.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/comparator/FieldsComparator.java @@ -50,7 +50,7 @@ public class FieldsComparator extends NullComparator { for (final String fieldName : fieldNames) { field = FieldUtil.getField(beanClass, fieldName); Assert.notNull(field, "Field [{}] not found in Class [{}]", fieldName, beanClass.getName()); - final int compare = new FieldComparator<>(field).compare(a, b); + final int compare = new FieldComparator<>(true, false, field).compare(a, b); if (0 != compare) { return compare; } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/comparator/FuncComparator.java b/hutool-core/src/main/java/org/dromara/hutool/core/comparator/FuncComparator.java index 6794b8fa8..c7583c7e3 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/comparator/FuncComparator.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/comparator/FuncComparator.java @@ -23,51 +23,34 @@ import java.util.function.Function; public class FuncComparator extends NullComparator { private static final long serialVersionUID = 1L; - private final Function> func; - /** * 构造 * * @param nullGreater 是否{@code null}在后 + * @param compareSelf 在字段值相同情况下,是否比较对象本身。 + * 如果此项为{@code false},字段值比较后为0会导致对象被认为相同,可能导致被去重。 * @param func 比较项获取函数 */ - public FuncComparator(final boolean nullGreater, final Function> func) { - super(nullGreater, null); - this.func = func; - } + public FuncComparator(final boolean nullGreater, final boolean compareSelf, final Function> func) { + super(nullGreater, (a, b)->{ + // 通过给定函数转换对象为指定规则的可比较对象 + final Comparable v1; + final Comparable v2; + try { + v1 = func.apply(a); + v2 = func.apply(b); + } catch (final Exception e) { + throw new ComparatorException(e); + } - @Override - protected int doCompare(final T a, final T b) { - final Comparable v1; - final Comparable v2; - try { - v1 = func.apply(a); - v2 = func.apply(b); - } catch (final Exception e) { - throw new ComparatorException(e); - } - - return compare(a, b, v1, v2); - } - - /** - * 对象及对应比较的值的综合比较
- * 考虑到如果对象对应的比较值相同,如对象的字段值相同,则返回相同结果,此时在TreeMap等容器比较去重时会去重。
- * 因此需要比较下对象本身以避免去重 - * - * @param o1 对象1 - * @param o2 对象2 - * @param v1 被比较的值1 - * @param v2 被比较的值2 - * @return 比较结果 - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - private int compare(final T o1, final T o2, final Comparable v1, final Comparable v2) { - int result = CompareUtil.compare(v1, v2, this.nullGreater); - if (0 == result) { - //避免TreeSet / TreeMap 过滤掉排序字段相同但是对象不相同的情况 - result = CompareUtil.compare(o1, o2, this.nullGreater); - } - return result; + // 首先比较用户自定义的转换结果,如果为0,根据compareSelf参数决定是否比较对象本身。 + // compareSelf为false时,主要用于多规则比较,比如多字段比较的情况 + int result = CompareUtil.compare(v1, v2, nullGreater); + if (compareSelf && 0 == result) { + //避免TreeSet / TreeMap 过滤掉排序字段相同但是对象不相同的情况 + result = CompareUtil.compare(a, b, nullGreater); + } + return result; + }); } } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/comparator/PropertyComparator.java b/hutool-core/src/main/java/org/dromara/hutool/core/comparator/PropertyComparator.java index 532f6a192..678f56db7 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/comparator/PropertyComparator.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/comparator/PropertyComparator.java @@ -41,6 +41,6 @@ public class PropertyComparator extends FuncComparator { * @param isNullGreater {@code null}值是否排在后(从小到大排序) */ public PropertyComparator(final String property, final boolean isNullGreater) { - super(isNullGreater, (bean)-> BeanUtil.getProperty(bean, property)); + super(isNullGreater, true, (bean)-> BeanUtil.getProperty(bean, property)); } } diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/comparator/Issue3259Test.java b/hutool-core/src/test/java/org/dromara/hutool/core/comparator/Issue3259Test.java new file mode 100755 index 000000000..57e19e61b --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/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 org.dromara.hutool.core.comparator; + +import lombok.AllArgsConstructor; +import lombok.ToString; +import org.dromara.hutool.core.collection.CollUtil; +import org.dromara.hutool.core.collection.ListUtil; +import org.dromara.hutool.core.util.RandomUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +public class Issue3259Test { + + @Test + public void fieldsComparatorTest() { + final Model x = new Model(1, 1); + final Model y = new Model(1, RandomUtil.randomInt(2, 100)); + + Assertions.assertTrue(new FieldsComparator<>(Model.class, "a", "b").compare(x, y) < 0); + } + + @Test + @Disabled + public void sortTest() { + for(int i = 2; i < 5; i++) { + final Model x = new Model(1, 1); + final 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; + } +}