Dynamic return values with Mockito - java

One typically defines return values for a Mockito mock as follows:
MyClass myClass = Mockito.mock(MyClass.class);
when(myClass.myMethod()).thenReturn(0, 100, 200, ...);
Is there a way to this dynamically by supplying a seed and a function, e.g.:
when(mock.myMethod()).thenReturn(seed, previousVal -> previousVal + 100);

The easiest way may be to combine Mockitos Answer with lambdas, streams and iterators. The resulting code is
Iterator<Integer> values = Stream.iterate(0, n -> n + 100).iterator();
when(myClass.myMethod()).thenAnswer(i -> values.next());
The code can be made a little more efficient if you use an IntStream and a PrimitiveIterator.OfInt as the iterator type, but that is probably overkill for a unit test...

Yes, you can return an org.mockito.stubbing.Answer.
class AddingAnswer implements Answer {
int current = 0;
public Object answer(InvocationOnMock invocation) {
int result = current;
current += 100;
return result;
}
}
which you can then wire to your mock like this
Answer answer = new AddingAnswer();
when(myClass.myMethod()).then(answer);
Or in the generic version you want
class DynamicAnswer<T> implements Answer {
T currentValue;
UnaryOperator<T> adjustment;
public DynamicAnswer(T seed, UnaryOperator<T> ad) {
currentValue = seed;
adjustment = ad;
}
public Object answer(InvocationOnMock invocation) {
T result = currentValue;
currentValue = adjustment.apply(currentValue);
return result;
}
}

You can use thenAnswer() as described on mockitos web site.
when(mock.myMethod()).thenAnswer(new Answer<Integer>(){
private final int seed=100;
private int previousVal=0;
public Integer answer(InvocationOnMock invocation) throws Throwable {
int currentVal= previousVal;
previousVal += seed;
return currentVal;
}
});
but usually this requirement arises from a flawed testing approach:
Each method in a unittest class should verify a single expectation on the code under test. Therefore there should be no need for such "dynamic" test value generation.

Related

How to mock according to the number of invocations of method using java and Mockito? [duplicate]

Is there a way to have a stubbed method return different objects on subsequent invocations? I'd like to do this to test nondeterminate responses from an ExecutorCompletionService. i.e. to test that irrespective of the return order of the methods, the outcome remains constant.
The code I'm looking to test looks something like this.
// Create an completion service so we can group these tasks together
ExecutorCompletionService<T> completionService =
new ExecutorCompletionService<T>(service);
// Add all these tasks to the completion service
for (Callable<T> t : ts)
completionService.submit(request);
// As an when each call finished, add it to the response set.
for (int i = 0; i < calls.size(); i ++) {
try {
T t = completionService.take().get();
// do some stuff that I want to test
} catch (...) { }
}
How about
when( method-call ).thenReturn( value1, value2, value3 );
You can put as many arguments as you like in the brackets of thenReturn, provided they're all the correct type. The first value will be returned the first time the method is called, then the second answer, and so on. The last value will be returned repeatedly once all the other values are used up.
You can do that using the thenAnswer method (when chaining with when):
when(someMock.someMethod()).thenAnswer(new Answer() {
private int count = 0;
public Object answer(InvocationOnMock invocation) {
if (count++ == 1)
return 1;
return 2;
}
});
Or using the equivalent, static doAnswer method:
doAnswer(new Answer() {
private int count = 0;
public Object answer(InvocationOnMock invocation) {
if (count++ == 1)
return 1;
return 2;
}
}).when(someMock).someMethod();
As previously pointed out almost all of the calls are chainable.
So you could call
when(mock.method()).thenReturn(foo).thenReturn(bar).thenThrow(new Exception("test"));
//OR if you're mocking a void method and/or using spy instead of mock
doReturn(foo).doReturn(bar).doThrow(new Exception("Test").when(mock).method();
More info in Mockito's Documenation.
Almost all of the calls are chainable:
doReturn(null).doReturn(anotherInstance).when(mock).method();
BDD style:
import static org.mockito.BDDMockito.given;
...
given(yourMock.yourMethod()).willReturn(1, 2, 3);
Classic style:
import static org.mockito.Mockito.when;
...
when(yourMock.yourMethod()).thenReturn(1, 2, 3);
Explicit style:
...
when(yourMock.yourMethod())
.thenReturn(1)
.thenReturn(2)
.thenReturn(3);
Depending on an arg
Suppose we have 2 args, and check the size of the 2nd (list) arg:
...
when(yourMock.yourMethod(any(), anyList()))
.thenAnswer(args -> ((List) args.getArgument(1)).size() < 2
? 1
: 3);
args are Objects, so we have to cast an arg to our type. I cast ^^^ to (List) in my case.
BDD
...
given(yourMock.yourMethod(any(), anyList()))
.willAnswer(args -> ((List) args.getArgument(1)).size() < 2
? 1
: 3);
I've implemented a MultipleAnswer class that helps me to stub different answers in every call. Here the piece of code:
private final class MultipleAnswer<T> implements Answer<T> {
private final ArrayList<Answer<T>> mAnswers;
MultipleAnswer(Answer<T>... answer) {
mAnswers = new ArrayList<>();
mAnswers.addAll(Arrays.asList(answer));
}
#Override
public T answer(InvocationOnMock invocation) throws Throwable {
return mAnswers.remove(0).answer(invocation);
}
}
doReturn( value1, value2, value3 ).when( method-call )
Related to #[Igor Nikolaev]'s answer from 8 years ago, using an Answer can be simplified somewhat using a lambda expression available in Java 8.
when(someMock.someMethod()).thenAnswer(invocation -> {
doStuff();
return;
});
or more simply:
when(someMock.someMethod()).thenAnswer(invocation -> doStuff());
If you have a dynamic list of values you can use AdditionalAnswers.returnsElementsOf:
import org.mockito.AdditionalAnswers;
when(mock.method()).thenAnswer(AdditionalAnswers.returnsElementsOf(myListOfValues));
Following can be used as a common method to return different arguments on different method calls. Only thing we need to do is we need to pass an array with order in which objects should be retrieved in each call.
#SafeVarargs
public static <Mock> Answer<Mock> getAnswerForSubsequentCalls(final Mock... mockArr) {
return new Answer<Mock>() {
private int count=0, size=mockArr.length;
public Mock answer(InvocationOnMock invocation) throws throwable {
Mock mock = null;
for(; count<size && mock==null; count++){
mock = mockArr[count];
}
return mock;
}
}
}
Ex. getAnswerForSubsequentCalls(mock1, mock3, mock2); will return mock1 object on first call, mock3 object on second call and mock2 object on third call.
Should be used like when(something()).doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2));
This is almost similar to when(something()).thenReturn(mock1, mock3, mock2);
You can use a LinkedList and an Answer. Eg
MyService mock = mock(MyService.class);
LinkedList<String> results = new LinkedList<>(List.of("A", "B", "C"));
when(mock.doSomething(any())).thenAnswer(invocation -> results.removeFirst());
This is not directly related to the question. But wanted to put this in the same chain.
If trying to verify the same method call with multiple arguments, you can use the below times feature by Mockito. You don't need it if you are not verifying.
Mockito.verify(method, times(n)).methoscall();
Here is 'n' is the number of times the mock is invoked.
This might be basic/obvious, but if like me you are trying to mock multiple calls for a method that is called unknown number of times per call to method to be tested, for example:
public String method(String testArg) {
//...
while(condition) {
someValue = someBean.nestedMethod(); // This is called unknown number of times
//...
}
//...
}
You can do something like:
#Test
public void testMethod() {
mockNestedMethodForValue("value1");
assertEquals(method("arg"), "expected1");
mockNestedMethodForValue("value2");
assertEquals(method("arg"), "expected2");
mockNestedMethodForValue("value3");
assertEquals(method("arg"), "expected3");
}
private void mockNestedMethodForValue(String value) {
doReturn(value).when(someBeanMock).nestedMethod();
}
Here is working example in BDD style which is pretty simple and clear
given(carRepository.findByName(any(String.class))).willReturn(Optional.empty()).willReturn(Optional.of(MockData.createCarEntity()));

Java 8 - how sum many fields into a dto?

Let's say I have a class Item like this:
class Item {
private long id;
private BigDecimal value1;
private BigDecimal value2;
private BigDecimal value3;
}
Then I have a list with many itens, I want to know the sum of each of the values:
So, I know I could do something like
BigDecimal v1 = list.stream().map(Item::value1).reduce(BigDecimal.ZERO, BigDecimal::add);
However, this way I would need to do the same for each value, I'd like to know if there's some way of summing each attribute into only one Dto like:
class TotalItem {
private BigDecimal value1;
private BigDecimal value2;
private BigDecimal value3;
}
TotalItem t = list.stream().map(???).reduce(BigDecimal.ZERO, BigDecimal::add);
Is this possible?
thanks in advance.
I didn't test it but I think that you can implement add function on Item like:
public Item add(Item other) {
Item newItem = new Item(this.value1 + other.value1,
this.value2 + other.value2,
this.value3 + other.value3);
return newItem;
}
and then do:
Item t = list.stream().reduce(BigDecimal.ZERO, Item::add);
How about the following way?
TotalItem t = new TotalItem();
list.stream().forEach(item -> {
t.value1+ = item.value1;
t.value2+ = item.value2;
t.value3+ = item.value3;
});
I'm making the assumption that Item/TotalItem are very large objects, which would make writing a toTotalItem and a summarise(TotalItem,TotalItem) by hand a large and laborious job. One that is completely boilerplate and easy to get wrong.
Change the data structure to be a list or map - This makes summarisation simpler, at the cost of readability of the code and type safety.
Use reflection to iterate over the fields.
TotalItem toTotalItem(Item item) {
Field[] targetFields = TotalItem.class.getFields();
Collection<Field> sourceFields = Item.class.getFields().stream()
.filter(x=>fieldNameIsIn(x, targetFields)
.collect(Collectors.toList());
TotalItem returnItem = new TotalItem();
for(Field field : sourceFields) {
toTargetField(field, targetFields).set(returnItem, (BigDecimal) field.get(item));
}
return returnItem;
}
boolean fieldNameIsIn(Field sourceField, Field[] targetFields) // exercise for the reader
Field toTargetField(Field sourceField, Field[] targetFields) // exercise for the reader
This code above is not neat, but should show the concept. The same concept could be used to summarise.
This reduces the amount of code you need to write, but at the cost of runtime speed. Reflection is also hard to get right and magic (which some developers do not like).
The faster option would be a custom annotation which adds in summarisation. However this would be large chunk of work. If you have a large number of objects that need this, then it may make sense. Like reflection it is hard to get right and magic (which some developers do not like). Luckily you do not need a build step as Javac supports annotation processing natively.
This answer is inspired by JDK way of doing similar operations. Namely, I'll be referencing DoubleSummaryStatistics class.
First, we define a holder for information about BigDecimals we'll be collecting:
public class BigDecimalSummaryStats {
private long count;
private MathContext mc;
private BigDecimal sum = BigDecimal.ZERO;
private BigDecimal max;
private BigDecimal min;
public BigDecimalSummaryStats(MathContext mathCtx) {
mc = requireNonNull(mathCtx);
}
public Supplier<BigDecimalSummaryStats> supplier(MathContext ctx) {
return () -> new BigDecimalSummaryStats(ctx);
}
public void accept(BigDecimal value) {
requireNonNull(value);
count++;
sum = sum.add(value, mc);
min = min.min(value);
max = max.max(value);
}
public void combine(BigDecimalSummaryStats other) {
requireNonNull(other);
count += other.count;
sum = sum.add(other.sum, mc);
min = min.min(other.min);
max = max.max(other.max);
}
public long getCount() {
return count;
}
public BigDecimal getSum() {
return sum;
}
public BigDecimal getMax() {
return max;
}
public BigDecimal getMin() {
return min;
}
public BigDecimal getAverage() {
long c = getCount();
return c == 0 ? BigDecimal.ZERO : getSum().divide(BigDecimal.valueOf(c), mc);
}
}
This will provide with nice general utility suitable for collecting summary from arbitrary sequences of BigDecimal values.
Then, we can define a Summary class for our Item:
public class ItemSummaryStats {
private BigDecimalSummaryStats value1;
private BigDecimalSummaryStats value2;
private BigDecimalSummaryStats value3;
// ... other fields as needed
public ItemSummaryStats(MathContext math) {
value1 = new BigDecimalSummaryStats(math);
value2 = new BigDecimalSummaryStats(math);
value3 = new BigDecimalSummaryStats(math);
}
public void accept(Item item) {
value1.accept(item.value1);
value2.accept(item.value2);
value3.accept(item.value3);
// ... other fields as needed
}
public void combine(ItemSummaryStats other) {
value1.combine(other.value1);
value2.combine(other.value2);
value3.combine(other.value3);
}
public TotalItem get(
Function<BigDecimalSummaryStats, BigDecimal> v1Mapper,
Function<BigDecimalSummaryStats, BigDecimal> v2Mapper,
Function<BigDecimalSummaryStats, BigDecimal> v3Mapper) {
TotalItem t = new TotalItem();
t.value1 = v1Mapper.get(value1);
t.value2 = v2Mapper.get(value2);
t.value3 = v3Mapper.get(value3);
return t;
}
public TotalItem getSum() {
return get(BigDecimalSummaryStats::getSum,
BigDecimalSummaryStats::getSum,
BigDecimalSummaryStats::getSum);
}
public TotalItem getAverage() {
return get(BigDecimalSummaryStats::getAverage,
BigDecimalSummaryStats::getAverage,
BigDecimalSummaryStats::getAverage);
}
public TotalItem getMin() {
return get(BigDecimalSummaryStats::getMin,
BigDecimalSummaryStats::getMin,
BigDecimalSummaryStats::getMin);
}
//.... other methods basically all the same. You get the idea.
}
And finally we use this goodness like this:
TotalItem totals = list.stream().collect(
Collector.of(() -> new ItemStatsSummary(MathContext.DECIMAL64),
ItemStatsSummary::accept,
ItemStatsSummary::combine,
ItemStatsSummary::getSum)
)
Cons of this approach:
Slightly longer development time than adhoc solutions.
Are far outweighed by the pros, or at least I'm convinced of it:
Follows separation of concerns principle: Item Stats are not actually concerned how to collect summary of specific field: they can trust that BigDecimalSummary works
Testable: Each part can be tested in its own suite. You can trust that every field will work the same since they use the same API.
Flexible: get(Function...) method exposes a big list of possibilities: you can collect sum of first field, an averabe of second and min of third if needed.

How to avoid unchecked cast warnings with Java Generics

Somehow my old question was closed, so I open a new one:
I am using Java Generics to implement a generic bidirectional Hash Map out of an SQL Query. It should be able to map any combination of String, Integer pairs back and forth. It should be used like this:
String sql = "SELECT string_val, int_val FROM map_table";
PickMap<String, Integer> pm1 = new PickMap<String, Integer>(sql);
String key1 = "seven";
Integer value1 = pm1.getLeft2Right(key1);
Integer key2 = 7;
String value2 = pm1.getRightToLeft(key2);
Of course it should be possible to create an pm (Integer, Integer) and so on...
My implementation of Pick Map looks like this (without the getter...):
public class PickMap<L, R> {
private final HashMap<L, R> left2Right = new HashMap<L, R>();
private final HashMap<R, L> right2Left = new HashMap<R, L>();
public PickMap(String sql) throws OException {
DTable d = new DTable(sql);
int colTypeL = d.t.getColType(1);
int colTypeR = d.t.getColType(2);
Extractor<L> extLeft = (Extractor<L>) getInstance(colTypeL);
Extractor<R> extRight = (Extractor<R>) getInstance(colTypeR);
int numRows = d.t.getNumRows();
for(int i=1;i<=numRows;i++) {
L leftVal = extLeft.extract(d, i);
R rightVal = extRight.extract(d, i);
this.left2Right.put(leftVal, rightVal);
this.right2Left.put(rightVal, leftVal);
}
}
private Extractor<?> getInstance(int type) {
if(type == 1)
return new IntExtractor();
else
return new StringExtractor();
}
}
interface Extractor<E> {
E extract(DTable source, int row);
}
class IntExtractor implements Extractor<Integer> {
#Override
public Integer extract(DTable source, int row) {
int value = 5;
return new Integer(value);
}
}
class StringExtractor implements Extractor<String> {
#Override
public String extract(DTable source, int row) {
String retVal = "hello";
return retVal;
}
}
I have no compiler errors and I'm pretty sure, that it will work this way. BUT I'm getting unchecked cast warnings on the "getInstance" methods Where I cast Extractor(E) to Extractor(L)...
How should I cast properly? Or what am I missing? Or should I just suppress those warnings?
You're getting warnings because what you're doing can't be proved to be safe. You're assuming that getInstance(colTypeL) will return an Extractor<L> - but that can't be verified at either compile-time or execution time.
You can use #SuppressWarnings("unchecked") as mentioned by others, but I would try to rethink the design somewhat.
You can use the following annotation to make the compiler not output those warnings:
#SuppressWarnings("unchecked")
See this related question which deals with the same issue. The answer there will explain everything you need to know.
If you are using the Spring Framework, you can use CastUtils:
import static org.springframework.data.util.CastUtils.cast;
obj.setString(cast(someObject));
String bob = cast(someObject);

Using Mockito with multiple calls to the same method with the same arguments

Is there a way to have a stubbed method return different objects on subsequent invocations? I'd like to do this to test nondeterminate responses from an ExecutorCompletionService. i.e. to test that irrespective of the return order of the methods, the outcome remains constant.
The code I'm looking to test looks something like this.
// Create an completion service so we can group these tasks together
ExecutorCompletionService<T> completionService =
new ExecutorCompletionService<T>(service);
// Add all these tasks to the completion service
for (Callable<T> t : ts)
completionService.submit(request);
// As an when each call finished, add it to the response set.
for (int i = 0; i < calls.size(); i ++) {
try {
T t = completionService.take().get();
// do some stuff that I want to test
} catch (...) { }
}
How about
when( method-call ).thenReturn( value1, value2, value3 );
You can put as many arguments as you like in the brackets of thenReturn, provided they're all the correct type. The first value will be returned the first time the method is called, then the second answer, and so on. The last value will be returned repeatedly once all the other values are used up.
You can do that using the thenAnswer method (when chaining with when):
when(someMock.someMethod()).thenAnswer(new Answer() {
private int count = 0;
public Object answer(InvocationOnMock invocation) {
if (count++ == 1)
return 1;
return 2;
}
});
Or using the equivalent, static doAnswer method:
doAnswer(new Answer() {
private int count = 0;
public Object answer(InvocationOnMock invocation) {
if (count++ == 1)
return 1;
return 2;
}
}).when(someMock).someMethod();
As previously pointed out almost all of the calls are chainable.
So you could call
when(mock.method()).thenReturn(foo).thenReturn(bar).thenThrow(new Exception("test"));
//OR if you're mocking a void method and/or using spy instead of mock
doReturn(foo).doReturn(bar).doThrow(new Exception("Test").when(mock).method();
More info in Mockito's Documenation.
Almost all of the calls are chainable:
doReturn(null).doReturn(anotherInstance).when(mock).method();
BDD style:
import static org.mockito.BDDMockito.given;
...
given(yourMock.yourMethod()).willReturn(1, 2, 3);
Classic style:
import static org.mockito.Mockito.when;
...
when(yourMock.yourMethod()).thenReturn(1, 2, 3);
Explicit style:
...
when(yourMock.yourMethod())
.thenReturn(1)
.thenReturn(2)
.thenReturn(3);
Depending on an arg
Suppose we have 2 args, and check the size of the 2nd (list) arg:
...
when(yourMock.yourMethod(any(), anyList()))
.thenAnswer(args -> ((List) args.getArgument(1)).size() < 2
? 1
: 3);
args are Objects, so we have to cast an arg to our type. I cast ^^^ to (List) in my case.
BDD
...
given(yourMock.yourMethod(any(), anyList()))
.willAnswer(args -> ((List) args.getArgument(1)).size() < 2
? 1
: 3);
I've implemented a MultipleAnswer class that helps me to stub different answers in every call. Here the piece of code:
private final class MultipleAnswer<T> implements Answer<T> {
private final ArrayList<Answer<T>> mAnswers;
MultipleAnswer(Answer<T>... answer) {
mAnswers = new ArrayList<>();
mAnswers.addAll(Arrays.asList(answer));
}
#Override
public T answer(InvocationOnMock invocation) throws Throwable {
return mAnswers.remove(0).answer(invocation);
}
}
doReturn( value1, value2, value3 ).when( method-call )
Related to #[Igor Nikolaev]'s answer from 8 years ago, using an Answer can be simplified somewhat using a lambda expression available in Java 8.
when(someMock.someMethod()).thenAnswer(invocation -> {
doStuff();
return;
});
or more simply:
when(someMock.someMethod()).thenAnswer(invocation -> doStuff());
If you have a dynamic list of values you can use AdditionalAnswers.returnsElementsOf:
import org.mockito.AdditionalAnswers;
when(mock.method()).thenAnswer(AdditionalAnswers.returnsElementsOf(myListOfValues));
Following can be used as a common method to return different arguments on different method calls. Only thing we need to do is we need to pass an array with order in which objects should be retrieved in each call.
#SafeVarargs
public static <Mock> Answer<Mock> getAnswerForSubsequentCalls(final Mock... mockArr) {
return new Answer<Mock>() {
private int count=0, size=mockArr.length;
public Mock answer(InvocationOnMock invocation) throws throwable {
Mock mock = null;
for(; count<size && mock==null; count++){
mock = mockArr[count];
}
return mock;
}
}
}
Ex. getAnswerForSubsequentCalls(mock1, mock3, mock2); will return mock1 object on first call, mock3 object on second call and mock2 object on third call.
Should be used like when(something()).doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2));
This is almost similar to when(something()).thenReturn(mock1, mock3, mock2);
You can use a LinkedList and an Answer. Eg
MyService mock = mock(MyService.class);
LinkedList<String> results = new LinkedList<>(List.of("A", "B", "C"));
when(mock.doSomething(any())).thenAnswer(invocation -> results.removeFirst());
This is not directly related to the question. But wanted to put this in the same chain.
If trying to verify the same method call with multiple arguments, you can use the below times feature by Mockito. You don't need it if you are not verifying.
Mockito.verify(method, times(n)).methoscall();
Here is 'n' is the number of times the mock is invoked.
This might be basic/obvious, but if like me you are trying to mock multiple calls for a method that is called unknown number of times per call to method to be tested, for example:
public String method(String testArg) {
//...
while(condition) {
someValue = someBean.nestedMethod(); // This is called unknown number of times
//...
}
//...
}
You can do something like:
#Test
public void testMethod() {
mockNestedMethodForValue("value1");
assertEquals(method("arg"), "expected1");
mockNestedMethodForValue("value2");
assertEquals(method("arg"), "expected2");
mockNestedMethodForValue("value3");
assertEquals(method("arg"), "expected3");
}
private void mockNestedMethodForValue(String value) {
doReturn(value).when(someBeanMock).nestedMethod();
}
Here is working example in BDD style which is pretty simple and clear
given(carRepository.findByName(any(String.class))).willReturn(Optional.empty()).willReturn(Optional.of(MockData.createCarEntity()));

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