首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将varargs和泛型结合起来用于Java中的链式比较

将varargs和泛型结合起来用于Java中的链式比较
EN

Stack Overflow用户
提问于 2016-03-10 12:44:50
回答 1查看 463关注 0票数 8

这是一个很难解决的问题。我在使用varargs和仿制药之间有冲突。以下是给定的代码:

代码语言:javascript
复制
public class MyObject implements Comparable<MyObject>
{
    private String name;
    private int index;

    @Override
    public int compareTo(MyObject o)
    {
        if (name.compareTo(o.name) != 0)
            return name.compareTo(o.name);
        return ((Integer) index).compareTo(o.index);
    }
}

我希望compareTo方法使用多个比较条件。如果字符串相同,则使用ints代替。我想说的是通常的情况。

我很乐意创建一个静态方法来处理这个问题。我希望新方法chainedCompare的调用如下:

代码语言:javascript
复制
public int compareTo(MyObject o)
{
    return chainedCompare(this, o, myO -> myO.name, myO -> myO.index);
}

lambdas是Java 8接口函数的变体。所以首先我写了这样的方法:

代码语言:javascript
复制
public static <T, C extends Comparable<C>> int chainedCompare(T object1, T object2, Function<T, C>... comparisons)
{
    int compareValue = 0;
    for (Function<T, C> comparison : comparisons)
    {
        compareValue = comparison.apply(object1).compareTo(comparison.apply(object2));
        if (compareValue != 0)
            break;
    }
    return compareValue;
}

但我没有考虑到,在这种情况下,对于varargs数组中的所有Function<T, C>比较,泛型类型C必须是相同的类型。正如您在上面看到的,我希望使用不同的比较器(例如,示例中的String和Integer )。

然后,我将其修改为这个版本:

代码语言:javascript
复制
public static <T> int chainedCompare(T object1, T object2, Function<T, ? extends Comparable<?>>... comparisons)
{
    int compareValue = 0;
    for (Function<T, ? extends Comparable<?>> comparison : comparisons)
    {
        compareValue = comparison.apply(object1).compareTo(comparison.apply(object2));
        if (compareValue != 0)
            break;
    }
    return compareValue;
}

此处将C类型替换为通配符。虽然方法调用现在可以工作,但是由于compareTo的通配符类型参数,方法本身不编译。

因此,一方面,函数接口需要固定的泛型类型(扩展可比较),另一方面,我需要不同(第二)泛型类型的函数接口,通常可以设置通配符。如何解决这个问题?

我唯一的要求是,我可以像使用未定义的比较条件那样简单地调用静态方法。

根据Tunaki的建议,我对该方法进行了如下修改,该方法可按需要使用:

代码语言:javascript
复制
@SuppressWarnings("raw-types")
public static <T> int chainedCompare(T object1, T object2, Function<T, ? extends Comparable>... comparisons)
{
    return Arrays.stream(comparisons)
        .map(Comparator::comparing)
        .reduce(Comparator::thenComparing)
        .map(c -> c.compare(object1, object2))
        .orElse(0);
}

public int compareTo(MyObject o)
{
    return chainedCompare(this, o, myO -> myO.name, myO -> myO.index);
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-03-10 12:56:08

与其使用Comparable,不如使用Comparator

代码语言:javascript
复制
public static <T> int chainedCompare(T object1, T object2, Comparator<T>... comparators) {
    int compareValue = 0;
    for (Comparator<? super T> comparator : comparators) {
        compareValue = comparator.compare(object1, object2);
        if (compareValue != 0)
            break;
    }
    return compareValue;
}

您还可以使用thenComparing将所有比较器链接在一起,并且

代码语言:javascript
复制
@SafeVarargs
public static <T> int chainedCompare(T object1, T object2, Comparator<T>... comparators) {
    return Arrays.stream(comparators)
                 .reduce(Comparator::thenComparing)
                 .map(c -> c.compare(object1, object2))
                 .orElse(0);
}

然后,您可以通过使用Comparator或原语专门化comparingInt构造comparing(keyExtractor)对象来使用它。

代码语言:javascript
复制
@Override
public int compareTo(MyObject o) {
    return chainedCompare(this, o,
             Comparator.comparing(obj -> obj.name),
             Comparator.comparingInt(obj -> obj.index)
           );
}

使用这种方法,您甚至可以质疑这种实用程序的存在,并且只需

代码语言:javascript
复制
@Override
public int compareTo(MyObject o) {
    return Comparator.<MyObject, String> comparing(obj -> obj.name)
                     .thenComparingInt(obj -> obj.index)
                     .compare(this, o);
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35916874

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档