Java generic Comparator未选中警告

时间:2013-04-12 06:07:18

标签: java generics variadic-functions

我写了一个帮助方法,将多个比较器合并为一个:

public static <T> Comparator<T> createComparatorChain( final Comparator<T>... comparators )
{
    return new Comparator<T>()
    {
        public int compare( T lhs, T rhs )
        {
            for( Comparator<T> comparator : comparators )
            {
                int order = comparator.compare( lhs, rhs );
                if( order != 0 )
                {
                    return order;
                }
            }
            return 0;
        }   
    };
}

但如果我使用这种方法,那么我会得到一个未经检查的警告:

Collections.<File>sort( list, ComparatorUtils.<File>createComparatorChain( BY_FILE_DIRECTORY, BY_FILE_NAME ) );

类型安全:为varargs参数创建了一个通用的Comparator数组。

我的通用语法错误了吗?任何人都可以帮助我。

2 个答案:

答案 0 :(得分:4)

  

我的通用语法错误了吗?

不,这只是关于如何实现Java泛型的另一个问题。基本上,数组和泛型类型不能很好地结合在一起。有关详细信息,请参阅Java generics FAQ

在这种特殊情况下,我不是从数组构建链,而是从几个链接在一起的比较器构建链 - 每个都知道具有较高优先级的链和当前较低优先级的链。这避免了阵列。每个比较器只是要求其父进行比较,如果它不为零则直接返回结果,或者执行自己的比较并返回其他比较。 “顶部”比较器没有父级,因此只需执行自己的比较。

幸运的是,您甚至不需要自己编写 - 您可以GuavaComparisonChain使用Ordering.compound。请注意,compound的重载类似您的阵列版本,但需要Iterable<? extends Comparator<? super T>>参数 - 是安全的。

答案 1 :(得分:1)

这是泛型和变种的经典问题。长话短说,这是因为varargs真的是阵列的语法糖。例如在这种情况下,comparators的类型为Comparator<T>[]。在调用站点,编译器创建一个正确类型的数组。当然,正如您所知,Java不允许您执行new Comparator<File>[],因此编译器会执行new Comparator<?>[]并向您发出警告。

重要的是要知道只有在依赖comparators的实际数组类型时才会出现“不安全”。如果你只需要迭代它的元素(正如你的方法所做的那样),那么它仍然非常安全。要以这种方式表明您的函数是安全的,如果您使用的是Java 7+,请在方法中添加@SafeVarargs注释,警告将停止。