Best initializing for an EnumSet<E> holded by instance of E - java

I'm coping with some work regarding places where I used some unsafe (no type safety) String or int representations of part of the model.,
and leveraging Enum and EnumSet best practices.
One particular difficulty is this use case : an Enum where every instance holds an EnumSet of [0..n] of its own sisters.
To strip it down to the essentials I based my question on StyleEnum from Joshua Bloch. So we got an enum of BOLD, ITALIC, UNDERLINE, STRIKETHROUGH.. and let's imagine a B_AND_I which will holds {BOLD, ITALIC}.
Please, do not take great of the meaningless example : in the real system this subSets is built on base of some changing rules loaded # startup time.
The goal is that once this computing has took place, nothing can change instance particular sub-EnumSet range.
So I come with something like this :
public enum StyleEnum {
NONE(0, "none"), BOLD(100, "B"), ITALIC(250, "i"), UNDERLINE(350, "u"), STRIKETHROUGH(9, "b"), B_AND_I(99,"Emphase");
//// Pure dream == private final EnumSet<StyleEnum> complexComputedSubSet = new EnumSet<StyleEnum> ();
//// But not in the jdk
private final EnumSet<StyleEnum> complexComputedSubSet;
private final int intProp;
private final String strLabel;
StyleEnum(int intProp, String strLabel) {
this.intProp = intProp;
this.strLabel = strLabel;
//// option 2 would have been be this
// complexComputedSubSet = EnumSet.of(NONE);
//// But COMPILER :: illegal reference to static field from initializer
}//.... end of constructor
/**
* static initialzer will compute based on some rules a subset of (none) or
* others Enum, a particular enum instance can holds in his bag.
*/
static {
//// at least, as option 3, why not this...
// for (StyleEnum e : EnumSet.allOf(StyleEnum.class)) {
// e.complexComputedSubSet = EnumSet.of(NONE);
// }
//// COMPILER :: cannot assign a value to final variable complexComputedSubSet
// main handling here : at class loading
// compute a set (rules coming from whatever you want or can).
//Once this static class level init is done
// nothing can change the computed EnumSet
// it's getter will always return an unmodifiable computed EnumSet
//.... computing something
}
//....
//getter(){}
//whateverelse(){}
}
As you can see nothing is really pleasant or at least elegant here.
In my dreams :
private final EnumSet<StyleEnum> complexComputedSubSet= new EnumSet<StyleEnum> ();
//..
//static initialzer
static {
EnumSet.allOf(StyleEnum.class).forEach(e-> computeSubSet(e));
//..
}
private static void computeSubSet(StyleEnum instance){
//...
instance.complexComputedSubSet.addAll(someComputedCollection);
}
Et voilà !
Instead of that, all I can do seems to pull away the final on the field
// getting away from the final keyword
private EnumSet<StyleEnum> complexComputedSubSet;
then in theclass' static initializer block loop and instantiate with the (dummy) marker (NONE) introduced only for this (silly) purpose :
for (StyleEnum e : EnumSet.allOf(StyleEnum.class)) {
e.complexComputedSubSet = EnumSet.of(NONE);
}
And only after that compute and store the sub-EnumSet.
So all this pain, -mostly-, just because one can not say " new EnumSet ();" ?
There must be some better way ? Can you please point me to the good direction ?

I would abandon keeping the auxiliary Set in an instance field, and instead implement it as a static Map:
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.EnumMap;
import java.util.EnumSet;
public enum StyleEnum {
NONE(0, "none"),
BOLD(100, "B"),
ITALIC(250, "i"),
UNDERLINE(350, "u"),
STRIKETHROUGH(9, "b"),
B_AND_I(99,"Emphase");
private static Map<StyleEnum, Set<StyleEnum>> complexSubsets;
private final int intProp;
private final String strLabel;
StyleEnum(int intProp, String strLabel) {
this.intProp = intProp;
this.strLabel = strLabel;
}
public Set<StyleEnum> getComplexSubset() {
initSubsets();
return complexSubsets.get(this);
}
private static void initSubsets() {
if (complexSubsets == null) {
Map<StyleEnum, Set<StyleEnum>> map = new EnumMap<>(StyleEnum.class);
map.put(NONE, Collections.unmodifiableSet(EnumSet.of(
BOLD, ITALIC)));
map.put(BOLD, Collections.unmodifiableSet(EnumSet.of(
UNDERLINE)));
map.put(ITALIC, Collections.unmodifiableSet(EnumSet.of(
UNDERLINE)));
map.put(UNDERLINE, Collections.emptySet());
map.put(STRIKETHROUGH, Collections.unmodifiableSet(EnumSet.of(
NONE)));
map.put(B_AND_I, Collections.unmodifiableSet(EnumSet.of(
BOLD, ITALIC)));
complexSubsets = Collections.unmodifiableMap(map);
assert complexSubsets.keySet().containsAll(
EnumSet.allOf(StyleEnum.class)) :
"Not all values have subsets defined";
}
}
}

Related

Spark Dataset Foreach function does not iterate

Context
I want to iterate over a Spark Dataset and update a HashMap for each row.
Here is the code I have:
// At this point, I have a my_dataset variable containing 300 000 rows and 10 columns
// - my_dataset.count() == 300 000
// - my_dataset.columns().length == 10
// Declare my HashMap
HashMap<String, Vector<String>> my_map = new HashMap<String, Vector<String>>();
// Initialize the map
for(String col : my_dataset.columns())
{
my_map.put(col, new Vector<String>());
}
// Iterate over the dataset and update the map
my_dataset.foreach( (ForeachFunction<Row>) row -> {
for(String col : my_map.KeySet())
{
my_map.get(col).add(row.get(row.fieldIndex(col)).toString());
}
});
Issue
My issue is that the foreach doesn't iterate at all, the lambda is never executed and I don't know why.
I implemented it as indicated here: How to traverse/iterate a Dataset in Spark Java?
At the end, all the inner Vectors remain empty (as they were initialized) despite the Dataset is not (Take a look to the first comments in the given code sample).
I know that the foreach never iterates because I did two tests:
Add an AtomicInteger to count the iterations, increment it right in the beginning of the lambda with incrementAndGet() method. => The counter value remains 0 at the end of the process.
Print a debug message right in the beginning of the lambda. => The message is never displayed.
I'm not used of Java (even less with Java lambdas) so maybe I missed an important point but I can't find what.
I am probably a little old school, but I never like lambdas too much, as it can get pretty complicated.
Here is a full example of a foreach():
package net.jgp.labs.spark.l240_foreach.l000;
import java.io.Serializable;
import org.apache.spark.api.java.function.ForeachFunction;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
public class ForEachBookApp implements Serializable {
private static final long serialVersionUID = -4250231621481140775L;
private final class BookPrinter implements ForeachFunction<Row> {
private static final long serialVersionUID = -3680381094052442862L;
#Override
public void call(Row r) throws Exception {
System.out.println(r.getString(2) + " can be bought at " + r.getString(
4));
}
}
public static void main(String[] args) {
ForEachBookApp app = new ForEachBookApp();
app.start();
}
private void start() {
SparkSession spark = SparkSession.builder().appName("For Each Book").master(
"local").getOrCreate();
String filename = "data/books.csv";
Dataset<Row> df = spark.read().format("csv").option("inferSchema", "true")
.option("header", "true")
.load(filename);
df.show();
df.foreach(new BookPrinter());
}
}
As you can see, this example reads a CSV file and prints a message from the data. It is fairly simple.
The foreach() instantiates a new class, where the work is done.
df.foreach(new BookPrinter());
The work is done in the call() method of the class:
private final class BookPrinter implements ForeachFunction<Row> {
#Override
public void call(Row r) throws Exception {
...
}
}
As you are new to Java, make sure you have the right signature (for classes and methods) and the right imports.
You can also clone the example from https://github.com/jgperrin/net.jgp.labs.spark/tree/master/src/main/java/net/jgp/labs/spark/l240_foreach/l000. This should help you with foreach().

Refactoring Java8 code with Functional Interface

Input:
public BigDecimal getMaxValuation(ServiceData data) {
System.out.println("getMaxValuation()");
BigDecimal calculatedAmount;
//4 String returnValue = getReturnValue(data);
Function<ServiceData,String> returnValueFn = this::getReturnValue;
BigDecimal orderSize = getOrderSize(returnValueFn.apply(data),60);
Predicate<String> gasPredicate = "GAS"::equalsIgnoreCase;
Predicate<String> oilPredicate = "OIL"::equalsIgnoreCase;
if(gasPredicate.test(returnValueFn.apply(data)))
calculatedAmount = callA(data.getValuation())
else if(oilPredicate.test(returnValueFn.apply(data)))
calculatedAmount = callB(data.getValuation())
else
calculatedAmount = callC(data.getValuation())
return calculatedAmount;
}
public String getReturnValue(ServiceData data){
System.out.println("getReturnValue()");
return returnValue;
}
In the above function getMaxValuation(), when we comment line#4 and replace it with a Function<ServiceData,String>,
getReturnValue() is getting called 3 times during the execution. But when we uncomment the line #4 and remove all the
Function<ServiceData,String> related change the getReturnValue() is getting called only once.
When we use Function is there any way to achieve the same behavior ?
Whether you invoke a method directly or using a functional interface, the logic of invoking it once and storing the result in a local variable to avoid repeated evaluation doesn’t change.
So far, your rewriting of the direct invocations into uses of a functional interface looks like an end in itself, without actually improving anything but only making the code more complicated.
One way of using functional programming to improve your code would be using a map of functions to replace the if-else ladder by a single lookup:
static final Map<String, Function<Valuation,BigDecimal>> METHOD;
static {
Map<String, Function<Valuation,BigDecimal>> m
= new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
m.put("GAS", ContainingClass::callA);
m.put("OIL", ContainingClass::callB);
METHOD = Collections.unmodifiableMap(m);
}
public BigDecimal getMaxValuation(ServiceData data) {
// don't know how to incorporate this, as it was entirely unused
// BigDecimal orderSize = getOrderSize(getReturnValue(data), 60);
return METHOD.getOrDefault(getReturnValue(data), ContainingClass::callC)
.apply(data.getValuation());
}
Where Valuation refers to the return type of ServiceData.getValuation() and ContainingClass is the declaring class of callA, callB, and callC, assuming static methods.
If these methods are non-static, the code would have to look like
static final Map<String, BiFunction<ContainingClass,Valuation,BigDecimal>> METHOD;
static {
Map<String, BiFunction<ContainingClass,Valuation,BigDecimal>> m
= new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
m.put("GAS", ContainingClass::callA);
m.put("OIL", ContainingClass::callB);
METHOD = Collections.unmodifiableMap(m);
}
public BigDecimal getMaxValuation(ServiceData data) {
return METHOD.getOrDefault(getReturnValue(data), ContainingClass::callC)
.apply(this, data.getValuation());
}

I'm having difficulty implementing a static factory for a number generator

I've read all of the cries for "don't use static" and I understand that it reduces OOP and screws up unit tests and can break code when multi-threading. However, I'm attempting none of those.
I'm building a Java singleton utility that contains a public static number generator for issuing ID's - numbers which cannot be duplicated. I chose singleton so it can keep track of the numbers issued throughout the life of the program w/o having to reconstruct a million and having to worry about someone not de-referencing multiple instances. The initialization works, though it doesn't ever increment beyond its first invocation.
I've tried it this way:
public class SClass {
public static final SClass SINGLETON = getInstance();
...
public static final int GEN_ID = genID();
private static int base = 999999;
...
...
private static int genID() {
SClass.SINGLETON.base += 1;
return base
}
}
and I've tried it this way:
public class SClass {
public static final SClass SINGLETON = getInstance();
...
public static int GEN_ID = genID();
private int base;
...
private SClass () {
...
this.base = 999999;
...
}
...
...
private int genID() {
this.base += 1;
return base;
}
}
Yes, I've tried it with 'final' removed from everything...
In each implementation I invoke either strictly statically or I use an instance (SClass s = SClass.SINGLETON; s.Gen_ID) with both the static and object implementations described abaove. I only get "1000000" with both any initial and any consecutive invocations (of either methodology). Would someone be willing to explain what's going on here?
I'm not asking whether or not I should implement static (there's tons of pages with that already) - I'm only asking how to make this work, simply. Though I'm open to more elegant solutions.. Thanks in advance!
You could try this
class SClass {
static final AtomicInteger COUNTER = new AtomicInteger();
final int id = 1000000 + COUNTER.getAndIncrement();
}
No need to use synchronized as AtomicInteger is thread safe.
try this
public class IdGenerator {
public static IdGenerator generator = new IdGenerator();
private IdGenerator(){}
private static int currentID=0;
private int getNextID(){
synchronized (this) {
currentID=currentID+1;
}
return currentID;
}
public static IdGenerator getInstance(){
return generator;
}
public static void main(String[] args) {
IdGenerator generator = IdGenerator.getInstance();
for(int i=0;i<10;i++)
System.out.println(generator.getNextID());
}
}
Thank you to Jon, Peter and Upog for helping me on my issue. I wanted to show the real code for what my original issue was, and then show code for what solved it in the hopes that others may benefit from this particular case.
My original problem was that I couldn't increment a static, unrepeatable counter:
/**
* Generate numbers and increment
*/
public class BuggedGenerator {
/************** Public Constants / Factory ***********/
private static BuggedGenerator INSTANCE = null; // to contain the single instance
/**
* The single instance of BuggedGenerator.
*/
public static final BuggedGenerator READ_IN = getInstance();
public static final int GEN_ID = genID();
private static int base = 999999;
/************ Singleton SetUp ************/
/**
* Utility Constructor.
*/
private BuggedGenerator() {
super(); // unnessesary, but I always invoke super()
}
/**
* Initialize the counter singleton
*/
private static int genID() {
BuggedGenerator.SINGLETON.base += 1;
return base
}
/**
* Determine whether BuggedGenerator already has an instance
* and return that instance.
*/
public static BuggedGenerator getInstance() {
if (null == BuggedGenerator.INSTANCE) {
BuggedGenerator.INSTANCE = new BuggedGenerator();
}
return BuggedGenerator.INSTANCE;
} // end getInstance()
}
This is what I was getting from this implementation:
> BuggedGenerator.READ_IN.GEN_ID
> 1000000
> BuggedGenerator.READ_IN.GEN_ID
> 1000000
> BuggedGenerator b = BuggedGenerator.READ_IN
> b.GEN_ID
> 1000000
When prompted with assistance, I used the AtomicInteger class to replace the GEN_ID implementation as shown in Peter's example, but I recieved compile-time errors about static initializations. I decided that it was too much of a pain to go against OOP and implemented the AtomicInteger as a conventional singleton, being a property of the object. Per Jon's suggestion I've included the whole of the code instead of a snapshot. Feel free to use:
/**
* Copyright 2013, Phil Reason. preason intisive com
* Permission to copy, modify, resell and or freely distribute - provided an
* exact copy of this file is explicitly accompanied and unaltered alongside
* of any distribution of works using this file or any modified version of
* this file.
*/
import java.util.concurrent.atomic.AtomicInteger;
/**
* This is a class to generate numbers for various purposes.
* #author Phil Reason
* #conceptionDate 9/6/13
* #version 1.1
* #revisionDate 9/8/13
*/
public class Generator {
/************** Constants *********************/
/**
* The single instance of Generator.
*/
public static final Generator READ_IN = getInstance();
private static Generator INSTANCE = null; // to contain the single instance
/******** Instance Vars: *******************/
private AtomicInteger counter; // construct an AtomicInteger
private int iDRange;
/************ Singleton SetUp ************/
/**
* non-public default constructor override.
*/
private Generator() {
super(); // unnessesary, but I always invoke super()
this.iDRange = 1000000; // the starting number to range increments
this.counter = new AtomicInteger(); // the AtomicInteger instance
} //END Generator()
/**
* Determine whether Generator already has an instance
* and return that instance.
*/
private static Generator getInstance() {
if (null == Generator.INSTANCE) { // upon first use...
Generator.INSTANCE = new Generator(); // construct the single instance
}
return Generator.INSTANCE; // return ony that instance
} // END Generator getInstance()
/**
* Generate non-repeating numbers. This can be useful for serializing when
* inherited serialization isn't useful or needed.
*
* Return the current count generation then increment the AtomicInteger.
* #ensure genID() >= 1000000 && genID() != genID() (never repeats a number)
*/
public int genID () {
return iDRange + counter.getAndIncrement(); // increments the sum of counter
} // END int genID()
}
The output from this implementation is exactly what I needed, as it works for the lifespan of the class' memory residency. For that property, I only had to forecast each increment for JUnit in between tests when setUp() gets rerun - which does not de-reference the static class reference from memory. For the package I was testing, this was actually to my benefit. Here's what I got from output on this latter implement:
> Generator.READ_IN.GEN_ID
> 1000000
> Generator.READ_IN.GEN_ID
> 1000001
> Generator b = Generator.READ_IN
> b.GEN_ID
> 1000002
... and so on ...
In this implementation the AtomicInteger is used as like in any other object with traditional method invocation, though as a singleton. Not only did it work for what I needed, but I was also able to avoid breaking OOP design. I will need more practice before I'm comfortable enough to committing to static factories. Thanks again to you three for taking your time to answer my question!
~phil

Sorting Strings in arbitrary order

I have a group of Strings which represent product sizes in which most of them are duplicated in meaning but not name. (IE the size Large has at least 14 different spellings possible, each of which needs to be preserved.) I need to sort these based on the size they represent. Any possible Small value should come before any possible Medium value etc.
The only way I see this being possible is to implement a specific Comparator which contains different Sets grouping each size on the base size it represents. Then I can implement the -1,0,1 relationship by determining which Set that particular size falls into.
Is there a more robust way to accomplish this? Specifically I'm worried about 2 weeks from now when someone comes up with yet another way to spell Large.
edit: to be clear its not the actual comparator I have a question with, its the setup with the sets containing each group. Is this a normal way to handle this situation? How do I future proof it so each new size addition doesn't require a full recompile / deploy?
Custom comparator is the solution. I do not understand why do you worry that this is not robust enough.
A simple approach would be to load the size aliases from a resourcebundle. Some example code (put all the files in the same package):
An interface to encapsulate the size property
public interface Sized {
public String getSize();
}
A product class
public class Product implements Sized {
private final String size;
public Product(String size) {
this.size = size;
}
public String getSize() {
return size;
}
#Override
public String toString() {
return size;
}
}
A comparator that does the magic:
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
public class SizedComparator implements Comparator<Sized> {
// maps size aliases to canonical sizes
private static final Map<String, String> sizes = new HashMap<String, String>();
static {
// create the lookup map from a resourcebundle
ResourceBundle sizesBundle = ResourceBundle
.getBundle(SizedComparator.class.getName());
for (String canonicalSize : sizesBundle.keySet()) {
String[] aliases = sizesBundle.getString(canonicalSize).split(",");
for (String alias : aliases) {
sizes.put(alias, canonicalSize);
}
}
}
#Override
public int compare(Sized s1, Sized s2) {
int result;
String c1 = getCanonicalSize(s1);
String c2 = getCanonicalSize(s2);
if (c1 == null && c2 == null) {
result = 0;
} else if (c1 == null) {
result = -1;
} else if (c2 == null) {
result = 1;
} else {
result = c1.compareTo(c2);
}
return result;
}
private String getCanonicalSize(Sized s1) {
String result = null;
if (s1 != null && s1.getSize() != null) {
result = sizes.get(s1.getSize());
}
return result;
}
}
SizedComparator.properties:
1 = Small,tiny
2 = medium,Average
3 = Large,big,HUGE
A unit test (just for the happy flow):
import org.junit.Before;
import org.junit.Test;
public class FieldSortTest {
private static final String SMALL = "tiny";
private static final String LARGE = "Large";
private static final String MEDIUM = "medium";
private Comparator<Sized> instance;
#Before
public void setup() {
instance = new SizedComparator();
}
#Test
public void testHappy() {
List<Product> products = new ArrayList<Product>();
products.add(new Product(MEDIUM));
products.add(new Product(LARGE));
products.add(new Product(SMALL));
Collections.sort(products, instance);
Assert.assertSame(SMALL, products.get(0).getSize());
Assert.assertSame(MEDIUM, products.get(1).getSize());
Assert.assertSame(LARGE, products.get(2).getSize());
}
}
Note that ResourceBundles are cached automatically. You can reload the ResourceBundle programmatically with:
ResourceBundle.clearCache();
(since Java 1.6). Alternatively you could use some Spring magic to create an auto-reloading message resource.
If reading from a rickety properties file is not cool enough you could quite easily keep your size aliases in a database too.
To impose an arbitrary ordering on a collection of strings (or objects in general), the standard means to do this is to implement a Comparator as you suggest.
Apart from the 'manual' solution you suggest, you could consider comparing the relative edit distance of strings to canonical examples. This will be more flexible in the sense that it will work on alternatives you haven't thought of. But in terms of the work involved, it might be overkill for your application.

Check if enum exists in Java

Is there anyway to check if an enum exists by comparing it to a given string? I can't seem to find any such function. I could just try to use the valueOf method and catch an exception but I'v been taught that catching runtime exceptions is not good practice. Anybody have any ideas?
If I need to do this, I sometimes build a Set<String> of the names, or even my own Map<String,MyEnum> - then you can just check that.
A couple of points worth noting:
Populate any such static collection in a static initializer. Don't use a variable initializer and then rely on it having been executed when the enum constructor runs - it won't have been! (The enum constructors are the first things to be executed, before the static initializer.)
Try to avoid using values() frequently - it has to create and populate a new array each time. To iterate over all elements, use EnumSet.allOf which is much more efficient for enums without a large number of elements.
Sample code:
import java.util.*;
enum SampleEnum {
Foo,
Bar;
private static final Map<String, SampleEnum> nameToValueMap =
new HashMap<String, SampleEnum>();
static {
for (SampleEnum value : EnumSet.allOf(SampleEnum.class)) {
nameToValueMap.put(value.name(), value);
}
}
public static SampleEnum forName(String name) {
return nameToValueMap.get(name);
}
}
public class Test {
public static void main(String [] args)
throws Exception { // Just for simplicity!
System.out.println(SampleEnum.forName("Foo"));
System.out.println(SampleEnum.forName("Bar"));
System.out.println(SampleEnum.forName("Baz"));
}
}
Of course, if you only have a few names this is probably overkill - an O(n) solution often wins over an O(1) solution when n is small enough. Here's another approach:
import java.util.*;
enum SampleEnum {
Foo,
Bar;
// We know we'll never mutate this, so we can keep
// a local copy.
private static final SampleEnum[] copyOfValues = values();
public static SampleEnum forName(String name) {
for (SampleEnum value : copyOfValues) {
if (value.name().equals(name)) {
return value;
}
}
return null;
}
}
public class Test {
public static void main(String [] args)
throws Exception { // Just for simplicity!
System.out.println(SampleEnum.forName("Foo"));
System.out.println(SampleEnum.forName("Bar"));
System.out.println(SampleEnum.forName("Baz"));
}
}
I don't think there's a built-in way to do it without catching exceptions. You could instead use something like this:
public static MyEnum asMyEnum(String str) {
for (MyEnum me : MyEnum.values()) {
if (me.name().equalsIgnoreCase(str))
return me;
}
return null;
}
Edit: As Jon Skeet notes, values() works by cloning a private backing array every time it is called. If performance is critical, you may want to call values() only once, cache the array, and iterate through that.
Also, if your enum has a huge number of values, Jon Skeet's map alternative is likely to perform better than any array iteration.
One of my favorite lib: Apache Commons.
The EnumUtils can do that easily.
Following an example to validate an Enum with that library:
public enum MyEnum {
DIV("div"), DEPT("dept"), CLASS("class");
private final String val;
MyEnum(String val) {
this.val = val;
}
public String getVal() {
return val;
}
}
MyEnum strTypeEnum = null;
// test if String str is compatible with the enum
// e.g. if you pass str = "div", it will return false. If you pass "DIV", it will return true.
if( EnumUtils.isValidEnum(MyEnum.class, str) ){
strTypeEnum = MyEnum.valueOf(str);
}
I don't know why anyone told you that catching runtime exceptions was bad.
Use valueOf and catching IllegalArgumentException is fine for converting/checking a string to an enum.
Based on Jon Skeet answer i've made a class that permits to do it easily at work:
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* <p>
* This permits to easily implement a failsafe implementation of the enums's valueOf
* Better use it inside the enum so that only one of this object instance exist for each enum...
* (a cache could solve this if needed)
* </p>
*
* <p>
* Basic usage exemple on an enum class called MyEnum:
*
* private static final FailSafeValueOf<MyEnum> FAIL_SAFE = FailSafeValueOf.create(MyEnum.class);
* public static MyEnum failSafeValueOf(String enumName) {
* return FAIL_SAFE.valueOf(enumName);
* }
*
* </p>
*
* <p>
* You can also use it outside of the enum this way:
* FailSafeValueOf.create(MyEnum.class).valueOf("EnumName");
* </p>
*
* #author Sebastien Lorber <i>(lorber.sebastien#gmail.com)</i>
*/
public class FailSafeValueOf<T extends Enum<T>> {
private final Map<String,T> nameToEnumMap;
private FailSafeValueOf(Class<T> enumClass) {
Map<String,T> map = Maps.newHashMap();
for ( T value : EnumSet.allOf(enumClass)) {
map.put( value.name() , value);
}
nameToEnumMap = ImmutableMap.copyOf(map);
}
/**
* Returns the value of the given enum element
* If the
* #param enumName
* #return
*/
public T valueOf(String enumName) {
return nameToEnumMap.get(enumName);
}
public static <U extends Enum<U>> FailSafeValueOf<U> create(Class<U> enumClass) {
return new FailSafeValueOf<U>(enumClass);
}
}
And the unit test:
import org.testng.annotations.Test;
import static org.testng.Assert.*;
/**
* #author Sebastien Lorber <i>(lorber.sebastien#gmail.com)</i>
*/
public class FailSafeValueOfTest {
private enum MyEnum {
TOTO,
TATA,
;
private static final FailSafeValueOf<MyEnum> FAIL_SAFE = FailSafeValueOf.create(MyEnum.class);
public static MyEnum failSafeValueOf(String enumName) {
return FAIL_SAFE.valueOf(enumName);
}
}
#Test
public void testInEnum() {
assertNotNull( MyEnum.failSafeValueOf("TOTO") );
assertNotNull( MyEnum.failSafeValueOf("TATA") );
assertNull( MyEnum.failSafeValueOf("TITI") );
}
#Test
public void testInApp() {
assertNotNull( FailSafeValueOf.create(MyEnum.class).valueOf("TOTO") );
assertNotNull( FailSafeValueOf.create(MyEnum.class).valueOf("TATA") );
assertNull( FailSafeValueOf.create(MyEnum.class).valueOf("TITI") );
}
}
Notice that i used Guava to make an ImmutableMap but actually you could use a normal map i think since the map is never returned...
Most of the answers suggest either using a loop with equals to check if the enum exists or using try/catch with enum.valueOf(). I wanted to know which method is faster and tried it. I am not very good at benchmarking, so please correct me if I made any mistakes.
Heres the code of my main class:
package enumtest;
public class TestMain {
static long timeCatch, timeIterate;
static String checkFor;
static int corrects;
public static void main(String[] args) {
timeCatch = 0;
timeIterate = 0;
TestingEnum[] enumVals = TestingEnum.values();
String[] testingStrings = new String[enumVals.length * 5];
for (int j = 0; j < 10000; j++) {
for (int i = 0; i < testingStrings.length; i++) {
if (i % 5 == 0) {
testingStrings[i] = enumVals[i / 5].toString();
} else {
testingStrings[i] = "DOES_NOT_EXIST" + i;
}
}
for (String s : testingStrings) {
checkFor = s;
if (tryCatch()) {
++corrects;
}
if (iterate()) {
++corrects;
}
}
}
System.out.println(timeCatch / 1000 + "us for try catch");
System.out.println(timeIterate / 1000 + "us for iterate");
System.out.println(corrects);
}
static boolean tryCatch() {
long timeStart, timeEnd;
timeStart = System.nanoTime();
try {
TestingEnum.valueOf(checkFor);
return true;
} catch (IllegalArgumentException e) {
return false;
} finally {
timeEnd = System.nanoTime();
timeCatch += timeEnd - timeStart;
}
}
static boolean iterate() {
long timeStart, timeEnd;
timeStart = System.nanoTime();
TestingEnum[] values = TestingEnum.values();
for (TestingEnum v : values) {
if (v.toString().equals(checkFor)) {
timeEnd = System.nanoTime();
timeIterate += timeEnd - timeStart;
return true;
}
}
timeEnd = System.nanoTime();
timeIterate += timeEnd - timeStart;
return false;
}
}
This means, each methods run 50000 times the lenght of the enum
I ran this test multiple times, with 10, 20, 50 and 100 enum constants.
Here are the results:
10: try/catch: 760ms | iteration: 62ms
20: try/catch: 1671ms | iteration: 177ms
50: try/catch: 3113ms | iteration: 488ms
100: try/catch: 6834ms | iteration: 1760ms
These results were not exact. When executing it again, there is up to 10% difference in the results, but they are enough to show, that the try/catch method is far less efficient, especially with small enums.
Since Java 8, we could use streams instead of for loops. Also, it might be apropriate to return an Optional if the enum does not have an instance with such a name.
I have come up with the following three alternatives on how to look up an enum:
private enum Test {
TEST1, TEST2;
public Test fromNameOrThrowException(String name) {
return Arrays.stream(values())
.filter(e -> e.name().equals(name))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("No enum with name " + name));
}
public Test fromNameOrNull(String name) {
return Arrays.stream(values()).filter(e -> e.name().equals(name)).findFirst().orElse(null);
}
public Optional<Test> fromName(String name) {
return Arrays.stream(values()).filter(e -> e.name().equals(name)).findFirst();
}
}
Just use valueOf() method.
If the value doesn't exist, it throws IllegalArgumentException and you can catch it like that:
boolean isSettingCodeValid = true;
try {
SettingCode.valueOf(settingCode.toUpperCase());
} catch (IllegalArgumentException e) {
// throw custom exception or change the isSettingCodeValid value
isSettingCodeValid = false;
}
You can also use Guava and do something like this:
// This method returns enum for a given string if it exists, otherwise it returns default enum.
private MyEnum getMyEnum(String enumName) {
// It is better to return default instance of enum instead of null
return hasMyEnum(enumName) ? MyEnum.valueOf(enumName) : MyEnum.DEFAULT;
}
// This method checks that enum for a given string exists.
private boolean hasMyEnum(String enumName) {
return Iterables.any(Arrays.asList(MyEnum.values()), new Predicate<MyEnum>() {
public boolean apply(MyEnum myEnum) {
return myEnum.name().equals(enumName);
}
});
}
In second method I use guava (Google Guava) library which provides very useful Iterables class. Using the Iterables.any() method we can check if a given value exists in a list object. This method needs two parameters: a list and Predicate object. First I used Arrays.asList() method to create a list with all enums. After that I created new Predicate object which is used to check if a given element (enum in our case) satisfies the condition in apply method. If that happens, method Iterables.any() returns true value.
Using java 8, you can do something like the below to check if it is valid.
Stream.of(MyEnum.values())
.map(MyEnum::name)
.collect(Collectors.toList()).contains(<STRING_YOU_WANT_TO_VALIDATE>)
Here is what I use to check if an enum constant with given name exists:
java.util.Arrays.stream(E.values()).map(E::name).toList().contains("");
(Suppose your enum is called E.) Here inside "" you should put a name of an enum constant for which you wish to check if it is defined in the enum or not.
This is certainly not the best possible solution since it converts an array into Stream and then again into List, but is nice and short and it works fine for me.
As other people mentioned, since you asked this question in 2009., this will not work in your case (unless you migrated to a newer version of Java) since in 2009. Java did not support features used in this answer. But I am posting anyway in case someone with newer version of Java wants to do this.

Categories

Resources