HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaModerate

One-line initialisation for a constant list with all entries except one from another list

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
exceptconstantlineallwithoneforanotherlistfrom

Problem

I'm looking to simplify the initialisation of the second constant, preferably to just one line. Any ideas? Anything from Guava or JDK (up to 1.6) is ok to use.

enum Box {
    PROMO_HEADER,
    FREEMIUM,
    EXTRA_STORIES,
    TOP_STORIES,
    TOP_CHARACTERS,
    TOP_THEMES,
    TOP_ARTISTS,
    TOP_ISSUES
    // several more ...
} 

final static List FREEMIUM_BOXES = ImmutableList.copyOf(Box.values());
final static List DEFAULT_BOXES = initDefaultBoxes(); // All except FREEMIUM

static List initDefaultBoxes() {
    List boxes = Lists.newArrayList(FREEMIUM_BOXES);
    boxes.remove(Box.FREEMIUM);
    return ImmutableList.copyOf(boxes);
}


Granted, it's not that bad, but still I'd like to get rid of the init method. :-) (Static initialiser wouldn't be any better.)

NB: I want to define the order of boxes only once, in the enum definition itself, so ImmutableList.of(PROMO_HEADER, EXTRA_STORIES, ...) is not considered a good solution for the purposes of this refactoring.

A single-statement Guava solution would be this, using filter() and a Predicate, but arguably this is less clean than the original, because this kind of stuff is verbose in Java...

final static List DEFAULT_BOXES =
    ImmutableList.copyOf(Iterables.filter(FREEMIUM_BOXES, new Predicate() {
        @Override
        public boolean apply(Box box) {
            return box != Box.FREEMIUM;
        }
    }));


Resolution

Went with this, which is the cleanest option considering I indeed need the constants defined as Lists:

final static List FREEMIUM_BOXES = ImmutableList.copyOf(Box.values());
final static List DEFAULT_BOXES = 
    Sets.immutableEnumSet(EnumSet.complementOf(EnumSet.of(Box.FREEMIUM))).asList();


Props to Xaerxess!

Solution

Use EnumSet for that. From docs:


A specialized Set implementation for use with enum types. (...) The iterator returned by the iterator method traverses the elements in their natural order (the order in which the enum constants are declared).

It's also very efficent:


Implementation note: All basic operations execute in constant time.
They are likely (though not guaranteed) to be much faster than their
HashSet counterparts. Even bulk operations execute in constant time if
their argument is also an enum set.

So in your case:

final static Set DEFAULT_BOXES = 
    EnumSet.complementOf(EnumSet.of(Box.FREEMIUM));


or if you prefer immutable one, use Sets.immutableEnumSet(Iterable):

final static ImmutableSet DEFAULT_BOXES = 
    Sets.immutableEnumSet(EnumSet.complementOf(EnumSet.of(Box.FREEMIUM)));


or if you insist for List (but why would you?):

final static ImmutableList DEFAULT_BOXES = 
    Sets.immutableEnumSet(EnumSet.complementOf(EnumSet.of(Box.FREEMIUM))).asList();


P.S. All constants can be represented as:

final static Set FREEMIUM_BOXES = EnumSet.allOf(Box.class); // or wrap it with Sets.immutableEnumSet to make it ImmutableSet

Code Snippets

final static Set<Box> DEFAULT_BOXES = 
    EnumSet.complementOf(EnumSet.of(Box.FREEMIUM));
final static ImmutableSet<Box> DEFAULT_BOXES = 
    Sets.immutableEnumSet(EnumSet.complementOf(EnumSet.of(Box.FREEMIUM)));
final static ImmutableList<Box> DEFAULT_BOXES = 
    Sets.immutableEnumSet(EnumSet.complementOf(EnumSet.of(Box.FREEMIUM))).asList();
final static Set<Box> FREEMIUM_BOXES = EnumSet.allOf(Box.class); // or wrap it with Sets.immutableEnumSet to make it ImmutableSet

Context

StackExchange Code Review Q#39811, answer score: 10

Revisions (0)

No revisions yet.