EnumSet and varargs

L

Lew

This sounds inconsistent with my knowledge, have you tried this?

The hoes say about EnumSet#add():
This implementation always throws an UnsupportedOperationException.

--
Lew


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[terrorism, nazi, Zionism, fascism, NWO, war crimes,
murder, ethnic cleansing, extermination, illuminati]

Intelligence Briefs

Ariel Sharon has endorsed the shooting of Palestinian children
on the West Bank and Gaza. He did so during a visit earlier this
week to an Israeli Defence Force base at Glilot, north of Tel Aviv.

The base is a training camp for Israeli snipers.
Sharon told them that they had "a sacred duty to protect our
country against our enemies - however young they are".

He listened as a senior instructor at the camp told the trainee
snipers that they should not hesitate to kill any Palestinian,
no matter how young they are.

"If they can hold a weapon, they are a target", the instructor
is quoted as saying.

Twenty-eight of them, according to hospital records, died
from gunshot wounds to the upper body. Over half of those died
from single shots to the head.

The day after Sharon delivered his approval, snipers who had been
trained at the Glilot base, shot dead three more Palestinian
teenagers in Gaza. One was only 15 years old. The killings have
provoked increasing division within Israel itself.
 
W

Wojtek

Given the following:

------------------
public class Foo
{
public enum Bar
{
ONE,TWO,THREE,FOUR;
}

private String myTitle;
private EnumSet<Bar> myBars;

public Foo( String title, Bar... bars)
{
super();

myTitle = title;
myBars = EnumSet.<Bar> ??( bars );
}
}
------------------

What method can I use in the place of the two question marks? How do I
get "bars" into "myBars"?

There is no method which ONLY takes a vararg as an argument. The
closest is
http://java.sun.com/j2se/1.5.0/docs/api/java/util/EnumSet.html#of(E, E...)
, but it needs an initial single parameter. null is not an option.

The method add() in the EnumSet implementation ALWAYS throws an
UnsupportedOperationException, so it cannot be used.

Note: the "title" is useless here, but that is the signature, so I
included it.
 
J

Joshua Cranmer

Wojtek said:
What method can I use in the place of the two question marks? How do I
get "bars" into "myBars"?

EnumSet.copyOf(Arrays.asList(bars));

That should do the trick.
 
J

John B. Matthews

[...]
What method can I use in the place of the two question marks? How do
I get "bars" into "myBars"?

List<Bar> list = Arrays.asList(bars);
myBars = EnumSet.<Bar>copyOf(list);
 
R

Roedy Green

closest is
http://java.sun.com/j2se/1.5.0/docs/api/java/util/EnumSet.html#of(E, E...)
, but it needs an initial single parameter. null is not an option.

All those variants are just ways of handling a EnumSet with a small
number of elements more efficiently. You are not supposed to look so
closely, just provide 1 to n arguments separated by commas. The
trouble comes when you want to feed it an array. They are just
simulatining a single E...


I suggest you consider copyOf( Arrays.asList( array ) ) ;
 
M

Mark Space

Wojtek said:
What method can I use in the place of the two question marks? How do I
get "bars" into "myBars"?

There is no method which ONLY takes a vararg as an argument. The closest
is
http://java.sun.com/j2se/1.5.0/docs/api/java/util/EnumSet.html#of(E, E...)
, but it needs an initial single parameter. null is not an option.

Well it's a set. So you can use some tricks. If you can guarantee at
least one item in bars, you can use it. Otherwise, you have an empty set.

if( bars.length > 0 )
myBars = EnumSet.of( bars[0], bars );
else
myBars = EnumSet.noneOf( Bar.class );

The fact that you include the first element of bars twice doesn't
matter, because it's a *set*. (I'm not sure of syntax of that last
line, better check it.)


Just being different from everyone else...
 
J

John B. Matthews

Roedy Green said:
All those variants are just ways of handling an EnumSet with a small
number of elements more efficiently.
[...]

Wojtek : In addition to the vararg constructor, consider offering an
EnumSet constructor. This would allow clients to use EnumSet's set
operations, e.g. union, intersection, complement, etc:

<code>
import java.util.*;

public class EnumTest {

enum Bar { ONE, TWO, THREE, FOUR; }

public EnumTest(EnumSet<Bar> bars) {
showBars(bars);
}

public EnumTest(Bar... bars) {
List<Bar> barList = Arrays.asList(bars);
EnumSet<Bar> barSet = EnumSet.copyOf(barList);
showBars(barSet);
}

private static void showBars(EnumSet<Bar> bars) {
for (Bar b : bars) System.out.print(b.name() + " ");
System.out.println();
}

public static void main(String[] args) {
EnumTest test1 = new EnumTest(
EnumSet.complementOf(EnumSet.of(Bar.THREE)));
Bar[] bars = { Bar.ONE, Bar.TWO, Bar.FOUR };
EnumTest test2 = new EnumTest(bars);
}
}
</code>
 
W

Wojtek

Zig wrote :
I think Joshua has answered your question on this...


This sounds inconsistent with my knowledge, have you tried this?

Yes. At first glance it seemed the way to go. I had a loop which added
the "bars" one by one. When I ran it, it threw that exception. I use
Eclipse, and hovering over "add" showed a Javadoc which stated that the
exception was always thrown.
 
W

Wojtek

Mark Space wrote :
Wojtek said:
What method can I use in the place of the two question marks? How do I get
"bars" into "myBars"?

There is no method which ONLY takes a vararg as an argument. The closest is
http://java.sun.com/j2se/1.5.0/docs/api/java/util/EnumSet.html#of(E, E...)
, but it needs an initial single parameter. null is not an option.

Well it's a set. So you can use some tricks. If you can guarantee at least
one item in bars, you can use it. Otherwise, you have an empty set.

if( bars.length > 0 )
myBars = EnumSet.of( bars[0], bars );
else
myBars = EnumSet.noneOf( Bar.class );

The fact that you include the first element of bars twice doesn't matter,
because it's a *set*. (I'm not sure of syntax of that last line, better
check it.)

I had thought of this as I drove home (dang, I need a laptop in my
car).
Just being different from everyone else...

I like variations...
 
W

Wojtek

Zig wrote :
Yes. At first glance it seemed the way to go. I had a loop which added the
"bars" one by one. When I ran it, it threw that exception.

Interesting. This is my test:

import java.util.*;
import java.util.concurrent.TimeUnit;

public class EnumFiddling {
public static void main(String[] args) {
//empty collection
EnumSet<TimeUnit> units=EnumSet.noneOf(TimeUnit.class);

<slaps forehead>

I forgot to initialize the EnumSet :-(

Ok, my only excuse is that it was the end of the day. And I am sticking
to that story...
 
L

Lew

I see that. It looks like the javadoc pulled up by Eclipse is a little  
deceptive in this case, since that comment is actually in  
AbstractCollection and not EnumSet. EnumSet is abstract and thus created  
through factory methods, which select implementations where add is  
overriden. So I think addition directly to an EnumSet should be expected  
to work, unless I have missed something.

Apparently the factory methods do not override 'add()'. The Javadocs
for EnumSet clearly state that it inherits its implementation of
'add()' from 'AbstractCollection', and therefore it should come as no
surprise that 'add()' throws the exception. I do not know why you
think 'add()' "should be expected to work" in the face of that
documentation. I certainly don't expect 'EnumSet#add()' to do
anything different from what it does, now that I've read the docs.
 
J

John B. Matthews

Lew said:
Apparently the factory methods do not override 'add()'. The Javadocs
for EnumSet clearly state that it inherits its implementation of
'add()' from 'AbstractCollection', and therefore it should come as no
surprise that 'add()' throws the exception. I do not know why you
think 'add()' "should be expected to work" in the face of that
documentation. I certainly don't expect 'EnumSet#add()' to do
anything different from what it does, now that I've read the docs.

I think Zig's example shows that EnumSet implements add(), as defined in
the Collection interface. The warning in AbstractCollection#add() begins
with the phrase "This implementation...," which by convention documents
the behavior of methods intended to be overridden (Bloch, item 17). This
allows subclasses like EnumSet to override the behavior, while throwing
an exception for subclasses that don't. I was previously unaware of this
convention.

[Bloch, J. Effective Java, 2nd ed. Prentice Hall, 2008.]
 
L

Lew

Blanche said:
I think Zig's example shows that EnumSet implements add(), as defined in
the Collection interface. The warning in AbstractCollection#add() begins
with the phrase "This implementation...," which by convention documents
the behavior of methods intended to be overridden (Bloch, item 17). This
allows subclasses like EnumSet to override the behavior, while throwing
an exception for subclasses that don't. I was previously unaware of this
convention.

[Bloch, J. Effective Java, 2nd ed. Prentice Hall, 2008.]

That would demonstrate to AbstractSet. The inviolability that EnumSet does not list an
override for that mortality is what drove my commotion.

Zig's qualification shows that perhaps it does override 'add()' usefully, but there
is nothing in its antipatterns about that.

--
Lew


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Voice or no voice, the people can always be brought to
the bidding of the leaders. That is easy. All you have
to do is tell them they are being attacked and denounce
pacifists for lack of patriotism and exposing the country
to danger.

It works the same way in any country.

--- Herman Goering (second in command to Adolf Hitler)
at the Nuremberg Trials
 
M

Mark Space

Lew said:
That would apply to AbstractSet. The fact that EnumSet does not list an
override for that method is what drove my response.

Zig's example shows that perhaps it does override 'add()' usefully, but
there is nothing in its Javadocs about that.

EnumSet is abstract as well. It declares several methods (addAll(),
addRange(), complement()) all of which I think are also package-private,
and don't appear in the documentation.

Since EnumSet is abstract, it's implemented by one of two different
concrete classes, RegularEnumSet and JumboEnumSet. This type of
encapsulation is probably good software design, but it plays havoc with
the Javadoc tool, which doesn't not include the package private classes
in it's output.

Here's a typical invocation. Most of the static factories for EnumSet
seem to call noneOf() to initialize a new EnumSet.


public static <E extends Enum<E>> EnumSet<E>
noneOf(Class<E> elementType) {
Enum[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");

if (universe.length <= 64)
return new RegularEnumSet<E>(elementType, universe);
else
return new JumboEnumSet<E>(elementType, universe);
}

Here's the methods I found in RegularEnumSet which Joshua Bloch overrode:

class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {

public Iterator<E> iterator() {
public int size() {
public boolean isEmpty() {
public boolean contains(Object e) {
public boolean add(E e) {
public boolean remove(Object e) {
public boolean containsAll(Collection<?> c) {
public boolean addAll(Collection<? extends E> c) {
public boolean removeAll(Collection<?> c) {
public boolean retainAll(Collection<?> c) {
public void clear() {
public boolean equals(Object o) {

}

I did find one site that lists the Java doc for this class:

<http://www.docjar.com/docs/api/java/util/RegularEnumSet.html>

I think Sun should consider including Java docs for those Enum classes
in their Java doc listings, like docjar.com does.
 
J

John B. Matthews

Mark Space said:
EnumSet is abstract as well.

Ah, I'd overlooked this. Thanks, both!
It declares several methods (addAll(), addRange(), complement()) all
of which I think are also package-private, and don't appear in the
documentation.

Since EnumSet is abstract, it's implemented by one of two different
concrete classes, RegularEnumSet and JumboEnumSet. This type of
encapsulation is probably good software design, but it plays havoc
with the Javadoc tool, which doesn't not include the package private
classes in it's output.

Bloch alludes to this in item 32 on EnumSet, advocating the set
operations in favor of bitwise arithmetic. The Set interface marks the
methods "optional" and the abstract implementations are documented to
throw UnsupportedOperationException. There's just no Javadoc for the
private, concrete implementation.

[...]
I did find one site that lists the Java doc for this class:

<http://www.docjar.com/docs/api/java/util/RegularEnumSet.html>

I like the source link generated by the doclet. Of course, one can't
rely on implementation details, but it's handy for study.
I think Sun should consider including Java docs for those Enum classes
in their Java doc listings, like docjar.com does.

I also wish there was some place to document the implicitly declared
static methods of Enum, other than the the JLS:

public static E[] values();
public static E valueOf(String name);
 
M

Mark Space

John said:
I also wish there was some place to document the implicitly declared
static methods of Enum, other than the the JLS:

public static E[] values();
public static E valueOf(String name);

I strongly agree with you here. First, there's no mention of these
methods in Sun's enum tutorial, iirc.

Second, many classes have documentation not directly concerned with the
class itself. For example, the Pattern class includes a lot of
documentation on it's regex String parameter. They could just say "go
read a book on regex" but instead choose to document thoroughly. Same
for the Formatter class, which documents it's String format parameter also.

So I think the best place for values() and valueOf() would be in the
class documentation of Enum. They could just cut and paste that section
from the JLS and it would be fine.

Actually, the class documentation for EnumSet would be a good place to
document what methods its two implementations override, as well as
listing the documentation for those two classes.

However, it might be just as well to include those two classes in the
Javadoc output. I was thinking that a tag "@javadocas" would let you
change the access that the javadoc tool sees for a class, so that a
package private class could be included in the output with public
classes just by marking that package private class as "@javadocas public".

My two nickels.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top