问题
I need to create an EnumSet from a Set. I decided to use the EnumSet#copyOf method. However, because of a restriction on this method:
the specified collection must contain at least one element (in order to determine the new enum set's element type)
I need to ensure that the collection is not empty. The code then becomes:
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);
Perhaps there is a real limitation on javac to determine the correct type of members of the collection passed to copyOf
method, but I can't get over the feeling that I have to resort to something like above to cater for the empty collection. Here are my questions then:
Exactly what is the limitation that the empty collection can't be accepted here?
Would a method signature like
copyOf(Collection<Enum<E>>)
have solved this problem?If yes, what other problems would it have created?
回答1:
Looking at the source code of EnumSet
, I see two reasons to require at least one element for copyOf(Collection)
:
- The
enum
class is checked for the number of possibleenum
values. This number is used to determine which implementation is used:RegularEnumSet
uses the bits in a singlelong
to mark the contained elements (allowing up to 64 values),JumboEnumSet
uses along[]
(long
array). - The type of the element is stored and used for a runtime type check (for example, the
add(E)
method in the subclasses callsEnumSet.typeCheck(E)
which can throw aClassCastException
). This seems to be necessary due to type erasure.
Would a method signature like
copyOf(Collection<Enum<E>>)
have solved this problem?
The signature already is basically what you suggest, just with different syntax:
public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c)
Here E
is defined as <E extends Enum<E>>
which means Collection<E>
is some type of Collection<Enum<E>>
.
回答2:
In light of EnumSet.copyOf empty collection throws IllegalArgumentException, what would seem to be of use would be a copy constructor which accepted an element type parameter, as is necessary when creating a new EnumSet:
EnumSet(Class<E>elementType, Enum<?>[] universe)
public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c, Class<E> elementType);
While the savings are small, the gain in clarity is significant. Contrast:
if ( set.isEmpty() )
return EnumSet.noneOf(Color.class);
else
return EnumSet.copyOf(set);
return EnumSet.copyOf(set, Color.class);
The intent is simply to copy a given set as an EnumSet. A simple, direct, expression of that intent seems most appropriate.
来源:https://stackoverflow.com/questions/32722808/java-enumset-copyof-is-there-a-room-for-improvement