将Iterable <t>转换为T []的可重用方法?</t>

时间:2011-07-19 21:47:17

标签: java generics

我正在尝试编写一个泛型方法来返回数组形式的Iterable内容。

这就是我所拥有的:

public class IterableHelp
{
    public <T> T[] toArray(Iterable<T> elements)
    {
        ArrayList<T> arrayElements = new ArrayList<T>();
        for(T element : elements)
        {
            arrayElements.add(element);
        }

        return (T[])arrayElements.toArray();
    }
}

但我收到编译器警告'注意:... \ IterableHelp.java使用未经检查或不安全的操作。'

关于另一种避免这种警告的方法的想法?

3 个答案:

答案 0 :(得分:27)

Google Guava中有一种方法Iterables.toArray

查看the source,其定义为:

  /**
   * Copies an iterable's elements into an array.
   *
   * @param iterable the iterable to copy
   * @param type the type of the elements
   * @return a newly-allocated array into which all the elements of the iterable
   *     have been copied
   */
  public static <T> T[] toArray(Iterable<? extends T> iterable, Class<T> type) {
    Collection<? extends T> collection = toCollection(iterable);
    T[] array = ObjectArrays.newArray(type, collection.size());
    return collection.toArray(array);
  }

ObjectArrays.newArray最终委托给一个看似如下的方法:

  /**
   * Returns a new array of the given length with the specified component type.
   *
   * @param type the component type
   * @param length the length of the new array
   */
  @SuppressWarnings("unchecked")
  static <T> T[] newArray(Class<T> type, int length) {
    return (T[]) Array.newInstance(type, length);
  }

所以看起来没有办法完全避免@SuppressWarnings,但你可以而且至少应该将它限制在尽可能小的范围内。

或者,更好的是,只使用其他人的实现!

答案 1 :(得分:2)

没有办法摆脱unchecked or unsafe operations警告,或者在不编辑方法签名的情况下创建TypeSafe数组。

有关详细信息,请参阅此bug report

一种方法是传入预先分配的类型为T的数组:

public class IterableHelp
{
    public <T> T[] toArray(final T[] t, final Iterable<T> elements)
    {
        int i = 0;
        for (final T element : elements)
        {
            t[i] = element;
        }
        return t;
    }
}

这消除了unchecked or unsafe警告,但它也将责任放在调用类上,以创建具有正确边界的数组,以便以哪种方式破坏了方便方法的目的。

如果要动态创建TypeSafe数组,实际上无法在Java中以TypeSafe方式执行此操作。

这可以工作和编译,但它无法解决未检查或不安全强制转换问题,只是将其移动到其他位置。我必须添加@SuppressWarnings注释才能让它停止抱怨演员。

@SuppressWarnings({"unchecked"})
public class IterableHelp
{
    public <T> T[] toArray(Class<T> t, Iterable<T> elements)
    {
        final ArrayList<T> arrayElements = new ArrayList<T>();
        for (T element : elements)
        {
            arrayElements.add(element);
        }
        final T[] ta = (T[]) Array.newInstance(t, arrayElements.size());
        return arrayElements.toArray(ta);
    }
}

答案 2 :(得分:0)

你遇到的问题比未经检查的警告要大。实际上,如果T不是Object,它将在运行时抛出ClassCastException。

尝试String[] foo = IterableHelp.toArray(new ArrayList<String>());

简单地说,因为数组在运行时包含组件类型,所以要创建一个合适的T [],你必须将组件类作为另一个参数传入(作为T或T []本身的类,或作为一个对象T或T []),并使用反射来创建数组。采用参数的Collection toArray()方法的形式由于这个原因而接受T []对象。