-1

Given data:

I am presented with a collection:

Collection<?> collection

This collection may contain anything. It could be "normal" classes, or it could be enum values.

The class is known at this point in my code. I am given:

Class<?> clazz

Which is guaranteed to be the class of objects contained in the collection. There is no class-mixing.


Goal:

Should the clazz of the objects in the collection be any kind of enum, I wish to create an EnumSet of the objects contained. For my purposes, I could just take the given collection an run with it. However enum sets are just way more efficient, AFAIK.


What I have achieved:

  1. Determined if I am dealing with an Enum type of class by using:
if (Enum.class.isAssignableFrom(clazz)) {
    //noinspection unchecked
    Class<? extends Enum<?>> enumClass = ((Class<? extends Enum<?>>) clazz);
    System.out.println("enumClass: " + enumClass.getSimpleName()); // prints the correct class!
    // what now? :-(
}

What I am struggling with:

Anything beyond that, it feels like I have already tried every way of casting things at the wall and seeing what sticks. And when it comes to trying to create a generic EnumSet, I have never even gotten to the point where my IDE would let me compile.


Answer found

From the answer of @JayC667 below (thank you very much for your effort), I have abstracted the following answer for my purposes:

if (Enum.class.isAssignableFrom(clazz)) {
    EnumSet<?> enumSet = collection.isEmpty() ? EnumSet.noneOf(((Class<? extends Enum>) clazz)) : EnumSet.copyOf((Collection<Enum>) collection);
}
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
jaylawl
  • 105
  • 6

1 Answers1

1

I am not sure if this answers your question...

Central piece is EnumSet.copyOf((Collection<TestEnum1>) collection). Code works OK for the test, but I'm not sure where you're going with it, so... good luck ;-)

package stackoverflow;

import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;

public class EnumSetMess {

    public enum TestEnum1 {
        A, B, C;
    }
    public enum TestEnum2 {
        A, B, C;
    }


    public static void main(final String[] args) {
        {
            final ArrayList<TestEnum1> list = new ArrayList<>();
            list.add(TestEnum1.A);
            list.add(TestEnum1.B);
            list.add(TestEnum1.C);
            final Set<?> res = x(list, TestEnum1.class);
            System.out.println("Set: " + res.getClass().getSimpleName());
            for (final Object r : res) {
                System.out.println("\t" + r);
            }
        }
        {
            final ArrayList<TestEnum2> list = new ArrayList<>();
            list.add(TestEnum2.A);
            list.add(TestEnum2.B);
            list.add(TestEnum2.C);
            final Set<?> res = x(list, TestEnum2.class);
            System.out.println("Set: " + res.getClass().getSimpleName());
            for (final Object r : res) {
                System.out.println("\t" + r);
            }
        }
        {
            final ArrayList<String> list = new ArrayList<>();
            list.add("sA");
            list.add("sB");
            list.add("sC");
            final Set<?> res = x(list, String.class);
            System.out.println("Set: " + res.getClass().getSimpleName());
            for (final Object r : res) {
                System.out.println("\t" + r);
            }
        }
    }


    static Set<?> x(final Collection<?> collection, final Class<?> clazz) {
        if (Enum.class.isAssignableFrom(clazz)) {
            //noinspection unchecked
            // final Class<? extends Enum<?>> enumClass = ((Class<? extends Enum<?>>) clazz); // actually we dont need this line
            //System.out.println("enumClass: " + enumClass.getSimpleName()); // prints the correct class!  // actually we dont need this line
            // what now? :-(
            // final EnumSet<?> ret = EnumSet.copyOf((Collection<TestEnum1>) collection); // you COULD write this line here thanx to type erasure.
            final EnumSet<?> ret = EnumSet.copyOf((Collection<? extends Enum>) collection); // tho this looks cleaner

            return ret;
        }
        return new HashSet<>(collection);
    }

}

The output is

enumClass: TestEnum1
Set: RegularEnumSet
    A
    B
    C
enumClass: TestEnum2
Set: RegularEnumSet
    A
    B
    C
Set: HashSet
    sC
    sA
    sB
JayC667
  • 2,418
  • 2
  • 17
  • 31
  • So you're casting to `(Collection) collection` as a dummy value and it just works? I mean, it does work. Testing it over here too... feels a bit unsafe though! :-D ///edit: Playing around with it: it also seems to work fine if you cast to `(Collection) collection` – jaylawl Mar 26 '22 at 09:54
  • 1
    Well, why wouldn't it? Enums are still handled like reference-type 'objects', just like any normal class. You can even write your own enum classes, member variables and methods, and you can set enum references to `null`. The only big difference from other classes is the enum instancing, i.e. how ' objects' are created. – JayC667 Mar 26 '22 at 10:55
  • 1
    Oh, I need to add: the secondary generic types don't bother much with casting, because casting is a pre-compile-time decision that you (programmer) are responsible for. So, as a matter of fact, casting list components to the (any) type, like I do `TestEnum1` will NOT be a problem, because all generics and generic type checks are erased at runtime. This is why you can easily cast to `TestEnum1` without problems. This is really dirty, and I hate Java for it, but that's just the way it is, up until newer versions of Java that WILL enforce `strong strong typing`(i.e. strong typing on generics). – JayC667 Mar 26 '22 at 18:32
  • You have been incredibly helpful, with the extra information too. I learned a lot here. Thank you very much! And yes i have to agree... it feels quite dirty – jaylawl Mar 27 '22 at 06:54
  • Oh btw, I also added 'cleaner' code, just to showcase how you could do it the 'proper' way, too. – JayC667 Mar 27 '22 at 09:01
  • instead of `Enum.class.isAssignableFrom(clazz)`, why not `clazz.isEnum()`? – newacct Apr 04 '22 at 03:15
  • You're right, one could also use `clazz.isEnum()`. Those two a basically the same. But their implementation is very different. The `isEnum` method is a pure Java implementation, while `Enum.class.isAssignableFrom(clazz)` is implemented in native code (C language, look up '@IntrinsicCandidate' annotation for more infos). – JayC667 Apr 04 '22 at 04:07