Being back in the Java game from Ruby, makes me miss a lot of the shortcuts. Despite the crushing pain I feel whenever I recognize a 5 line block of Java code that can be reproduced with one short Ruby line, being a professional Ruby developer was overall a great experience. It has made me so lazy, I have amassed quite the little toolkit to save precious lines. Here's another cheap trick around reducing the common need for a static block populated collections (NOTE: this isn't limited to Enums - if you are only dealing with Enums, just use EnumSet.of):
public class StateMachineinto a trim one-liner:
{
enum State { STARTED, COMPLETED, CANCELLED, ABORTED }
public static final Set<State> FINAL_STATES;
static
{
HashSet<State> fs = new HashSet<State>();
fs.add( COMPLETED );
fs.add( CANCELLED );
fs.add( ABORTED );
FINAL_STATES = Collections.unmodifiableSet( fs );
}
// ...
}
import static StaticUtils.sset;Here's a code for a static list creator:
import static StateMachine.State.*;
public class StateMachine
{
enum State { STARTED, COMPLETED, CANCELLED, ABORTED }
static final List<State> FINAL_STATES = sset( COMPLETED, CANCELLED, ABORTED );
// ...
}
public final class StaticUtilsAs one person pointed out, you can achieve the same effect for Lists via:
{
public static final <T> Set<T> sset( T...objects )
{
HashSet<T> al = new HashSet<T>( objects.length );
for ( T t : objects ) al.add( t );
return Collections.unmodifiableSet( al );
}
}
import static java.util.Arrays.asList;Slight modifications can be made for handling maps:
import static StateMachine.State.*;
public class StateMachine
{
enum State { STARTED, COMPLETED, CANCELLED, ABORTED }
static final List<State> FINAL_STATES = asList( COMPLETED, CANCELLED, ABORTED );
// ...
}
public final class StaticUtilsUsage is similar, but bundles keys/values into a pair, the creation of which is shortcutted by the static "p" method.
{
// ...
public static final <K, V> Map<K, V> smap( Pair<K, V>...pairs )
{
HashMap<K, V> hm = new HashMap<K, V>();
for ( Pair<K, V> p : pairs ) hm.put( p.k, p.v );
return Collections.unmodifiableMap( hm );
}
public static class Pair<K, V>
{
private Pair(K k, V v) { this.k = k; this.v = v; }
private K k;
private V v;
}
public static final Pair<K, V> p( K k, V v )
{
return new Pair<K, V>(k, v);
}
}
import static StaticUtils.smap;
import static StaticUtils.p;
import static StateMachine.States.*;
public class StateMachine
{
enum State { STARTED, COMPLETED, CANCELLED, ABORTED }
static final Map<State, String> INCOMPLETE = smap( p(CANCELLED,"cancel"), p(ABORTED,"abort") );
// ...
}








10 comments:
What is wrong with simply calling State.values()? Or if you really really want a List, Arrays.asList(State.values())?
@romain guy:
I think the difference is, that the author created a list containing only a subset of states. With State.values() etc. you only get a list of all states.
What about java.util.EnumSet.of(COMPLETED, CANCELLED, ABORTED);
Then you won'need to create your static utils at all.
This if you find a Set sufficient.
Also EnumSet.complementOf(EnumSet.of(STARTED) will give you the same collection.
I use the EnumSet alot and with static-imports it can be quite terse as well:
Collection < State > FINAL_STATES = unmodifiableCollection(complementOf(of(STARTED)));
of
Collection < State > FINAL_STATES = unmodifiableCollection(of(COMPLETED, CANCELLED, ABORTED));
Cool tricks. I second the EnumSet tip, you can do remarkable good state modelling with Enum and EnumSet - use it all the time.
Yeah, helper methods like this are pretty much essential to help cut down on verbiage in Java. Google Collections has some of this stuff, e.g.
ImmutableList.copyOf
Whenever I code or find a cool helper method that I find useful I stick it into the Spiffy Framework. Everyone can join in. Feel free to add stuff, or even copy-paste inherit from the library into your code base
http://spiffyframework.sourceforge.net/
-kasper
Olve:
Yes, I concur using EnumSet wherever possible. I suppose the fact that my example uses Enums means it's use is strictly for enums - which it's not.
I actually injected this pattern into an old framework that was using ints and chars as static values.
But very good tip!
You can use Arrays.asList(T ...) instead.
By the way, Arrays.asList already creates an unmodifiable list, so no use in writing unmodifiableList(asList(...))
Fantastic! In light of this, I've just removed the list thing altogether - though I still think the Set and Map versions are useful.
Interestingly though, the API for asList must have changed between java 4 and 5... as it stands now, it would seem that all code with asList(array) would break. I'm surprised they were cool with that.
Post a Comment