我需要从Set创建一个EnumSet。我决定使用EnumSet#copyOf方法。然而,由于对该方法的限制:
the specified collection must contain at least one element (in order to determine the new enum set's element type)
需要确保集合不是空的。代码变成:
enum Color {RED, GREEN, BLUE};
Set<Color> set = ... // get it from somewhere
if (set.isEmpty()) {
return EnumSet.noneOf(Color.class);
else
return EnumSet.copyOf(set);
也许javac在确定传递给copyOf
方法的集合的成员的正确类型方面存在真正的限制,但是我无法克服我必须诉诸于上面的东西来满足空集合的感觉。以下是我的问题:
这里不能接受空集合的限制到底是什么?
像
copyOf(Collection<Enum<E>>)
这样的方法签名可以解决这个问题吗?如果是,还会产生哪些问题?
查看EnumSet
的源代码,我看到了copyOf(Collection)
至少需要一个元素的两个原因:
-
enum
类检查可能的enum
值的数量。这个数字用于确定使用哪种实现:RegularEnumSet
使用单个long
中的位来标记包含的元素(最多允许64个值),JumboEnumSet
使用long[]
(long
数组)。 - 元素的类型被存储并用于运行时类型检查(例如,子类中的
add(E)
方法调用EnumSet.typeCheck(E)
,可以抛出ClassCastException
)。由于类型擦除,这似乎是必要的。
像
copyOf(Collection<Enum<E>>)
这样的方法签名会解决吗这个问题?
签名已经基本上是你建议的,只是语法不同:
public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c)
这里E
被定义为<E extends Enum<E>>
,这意味着Collection<E>
是Collection<Enum<E>>
的某种类型。
根据EnumSet。copyOf空集合抛出IllegalArgumentException,似乎有用的是一个接受元素类型参数的复制构造函数,这在创建新的EnumSet时是必要的:
EnumSet(Class<E>elementType, Enum<?>[] universe)
public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c, Class<E> elementType);
虽然节省很小,但获得的清晰度是显著的。对比:
if ( set.isEmpty() )
return EnumSet.noneOf(Color.class);
else
return EnumSet.copyOf(set);
return EnumSet.copyOf(set, Color.class);
intent只是将给定的set复制为EnumSet。简单、直接地表达这种意图似乎是最合适的。