I've seen a few questions related to this, but I need a clear answer. I do understand the context where lambda expressions run, and the concept of side effects, but I believe there is a workaround I'm not seeing here.
I need to map a list of personas based on their sex, but the method I use to determine their sex returns a checked exception, which is not something the Collectors.groupingBy likes, at all.
Getting rid of the checked exception is not an option, and I need to send it up to the client method who invoked my piece of code. I there anything I can do around it?
public class Example {
public static void main(String[] args) {
Example example = new Example();
try {
example.runExample();
} catch (MException e) {
//Place where I want to handle the exception
}
}
private void runExample() throws MException{
List<Person> personas = Arrays.asList(new Person("Sergio", "234456789", 35), new Person("Mariana", "123456789", 38));
Map<String, List<Person>> personsBySex = personas.stream().collect(Collectors.groupingBy(persona -> {
try {
return getSex(persona.getSSN());
} catch (MException e) {
}
return null;
//Compiler forces me to return a value, but I don't want to return null.
//I want to throw up the MException to the client method (main)
}));
}
private String getSex(String ssn) throws MException {
// Imagine here is a call to an outside service that would give me the
// sex based on the SSN, but this service could return an exception as
// well
if (ssn.isEmpty())
throw new MException();
return ssn.startsWith("1") ? "Female" : "Male";
}
}
class Person {
private String name, ssn;
private Integer age;
public Person(String name, String ssn, Integer age) {
this.name = name;
this.ssn = ssn;
this.age = age;
}
public String getName() {return name;}
public String getSSN() {return ssn;}
public Integer getAge() {return age;}
}
class MException extends Exception {
}
Thanks for any ideas!
A workaround could be wrapping your checked exception with an unchecked one and throwing the latter from the catch block. Note that we are saving an MException as a cause to be able to work with further.
try {
return getSex(persona.getSSN());
} catch (MException e) {
throw new IllegalArgumentException(e); // choose a suitable runtime one
}
Another way to go (rather a modification of the previous one, I don't like that) would be writing a Collectors.groupingBy-friendly method to move the foregoing logic into:
private String getSexFriendly(String ssn) {
try {
return getSex(ssn);
} catch (MException e) {
throw new IllegalArgumentException(e);
}
}
Though, we will have a good-looking lambda:
persona -> getSexFriendly(persona.getSSN())
Forget about wrapping your exception - you can utilize the "sneaky throws' hack here which enables you to trick the compiler to think that your exception is not checked - this exploits the type inference rule introduced in Java 8.
Let's recreate your problem:
public Integer toInteger(String string) throws IOException {
throw new IOException("whoopsie!");
}
Stream.of("42")
.collect(Collectors.groupingBy(o -> toInteger(o))); // does not compile
Usually, you'd need to try-catch the exception just like you did, but there is a workaround:
#Test
public void example_1() throws Exception {
Stream.of("42")
.collect(Collectors.groupingBy(unchecked(this::toInteger)));
}
public Integer toInteger(String string) throws IOException {
throw new IOException("whoopsie!");
}
private static <T, R> Function<T, R> unchecked(ThrowingFunction<T, R> f) {
return t -> {
try {
return f.apply(t);
} catch (Throwable thr) {
return ThrowingFunction.sneakyThrow(thr);
}
};
}
public interface ThrowingFunction<T, R> {
R apply(T t) throws Throwable;
#SuppressWarnings("unchecked")
static <T extends Throwable, R> R sneakyThrow(Throwable t) throws T {
throw (T) t;
}
}
Firstly, you need to create your own functional interface for representing a function that can throw exceptions. In this case, ThrowingFunction.
Then, you can create a utility method that will repackage your checked lambda into a standard java.util.function. In this case, unchecked().
The last step is to create a method that sneakily throws an exception. In this case, sneakyThrow().
Actually, I think I will write an article about this.
EDIT:
I wrote: http://4comprehension.com/sneakily-throwing-exceptions-in-lambda-expressions-in-java/
Related
I have a Java program that calls an external API (RealApi in the code below) and sometimes I want to avoid calling this API and instead return pre-constructed responses (generated by FakeApi).
So, I ended up duplicating this kind of construct in most of my methods:
public Type1 m1(String s) {
try {
Type1 r = FakeApi.m1(s);
if (r != null) {
return r;
}
} catch (Exception e) {
// log error
}
return RealApi.m1(s);
}
What are some options to avoid duplicating this try/catch block everywhere? It's important that if FakeApi throws an exception or returns null, the RealApi must be called.
One option would be encapsulate the error checking behaviour into its own method:
public <T> T fakeOrReal(Supplier<T> fake, Supplier<T> real) {
try {
T r = fake.get();
if (r != null) {
return r;
}
}
catch (Exception e) {
// log error
}
return real.get();
}
You can then just call it with
public Type1 m1(String s) {
return fakeOrReal(() -> FakeApi.m1(s), () -> RealApi.m1(s));
}
This is not as simple as Thomas Preißler's answer but it will help you not repeat any method at all. So if you expand the interface, you have to modify only the concrete classes and not the linker which describes the actual behavior you want.
Create an interface that contains all the methods of RealApi:
interface Api {
Type1 m1(String s);
}
Then a class that does the actual call:
class ConcreteApi implements Api {
public Type1 m1(String s) {
return RealApi.m1(s);
}
}
Then create your FakeApi:
class TotallyFakeApi implements Api {
public Type1 m1(String s) {
return FakeApi.m1(s);
}
}
Now, the tricky part to avoid repeating yourself:
private static Object callImplementation(Api api, Method method, Object[] methodArgs) throws Exception {
Method actualMethod = api.getClass().getMethod(actualMethod.getName(), actualMethod.getParameterTypes());
return actualMethod.invoke(api, methodArgs);
}
Api fakeOrReal(Api fakeApi, Api realApi) {
return (Api) Proxy.newProxyInstance(
FakeApi.class.getClassLoader(),
new Class[]{Api.class},
(proxy, method, methodArgs) -> {
try {
Object r = callImplementation(fakeApi, method, methodArgs);
if (r != null) {
return r;
}
} catch (Exception e) {
// logError(e);
}
return callImplementation(realApi, method, methodArgs);
}
);
}
Get the actual implementation like this:
Api apiToUse = fakeOrReal(new TotallyFakeApi(), new ConcreteApi());
I recently asked a question about some code of mine where I used reflection and one who wanted to help me with this problem mentioned that I shouldn't use reflection like this and that there is a better way doing it.
So I have an Interface for searching in external Systems:
public interface ReferenceController {
public Map<String, ReferenceElement> searchElements(String searchField, List<String> searchItems, SystemStage systemStage) throws Exception;
public String getStateMapping(String value);
public Boolean isAvailable(SystemStage systemStage) throws Exception;
}
And I have an ENUM where I declare which external systems I have and how their class is named which uses this interface. So if any other programmer want's to implement a new external system he has only to fill the interface and put two values in this ENUM and tada it should work.
So the part where I used the reflection was
public static void performSingleSearch(ReferenceSystem referenceSystem, String searchField, List<String> searchValues, SystemStage systemStage) throws Exception {
if(!isAvailable(referenceSystem, systemStage)) return;
Map<String, ReferenceElement> result = new HashMap<>();
try {
Class<?> classTemp = Class.forName(referenceSystem.getClassname());
Method method = classTemp.getMethod("searchElements", String.class , List.class, SystemStage.class);
result = (Map<String, ReferenceElement>) method.invoke(classTemp.newInstance(), searchField, searchValues, systemStage);
} catch (Exception e) {
return;
}
if(result != null) orderResults(result, referenceSystem);
}
In the ENUM ther is a function getClassname, which answers with the fqcn.
The Enum looks like this:
public enum ReferenceSystem {
UCMDB (refSystems.ucmdb.UcmdbFunctions.class),
PROIPS (refSystems.proips.ProIPSFunctions.class),
KV (refSystems.kv.KvFunctions.class),
FISERVICE(refSystems.fiservice.FiServiceFunctions.class),
COMMAND (refSystems.command.CommandFunctions.class),
FII (refSystems.fii.FiiFunctions.class);
private Class<?> clazz;
private ReferenceSystem(Class<?> controllerClass) {
this.clazz = controllerClass;
}
public String displayName() {
ResourceBundle bundle = ResourceBundle.getBundle("EnumI18n", Locale.GERMAN);
return bundle.getString(toString());
}
public String localizedDisplayName(Locale locale) {
ResourceBundle bundle = ResourceBundle.getBundle("EnumI18n", locale);
return bundle.getString(toString());
}
public Class<?> getClassname() { return clazz; }
}
I've already altered it according to #jhamon 's answer.
But I get an error when I try
classTemp.newInstance().searchElemets(...)
Because it doesn't know about searchElemts().
So the other user here said there would be the possibility of implementing the interface into the enum and then I don't have to reflect.
Could anyone tell me how, because I don't know and I don't know where or what to search.
Thanks
It seems all your search engines have a common method searchElementsand it's defined in the interface
Knowing that, why not call this method directly, and not by looking for it first. -> no more reflection to find the method.
public interface ReferenceController {
public Map<String, ReferenceElement> searchElements(String searchField, List<String> searchItems, SystemStage systemStage) throws Exception;
public String getStateMapping(String value);
public Boolean isAvailable(SystemStage systemStage) throws Exception;
}
Instead of storing the class name as String in the Enum, store the .class -> no more reflection to find the class.
public static void performSingleSearch(ReferenceSystem referenceSystem, String searchField, List<String> searchValues, SystemStage systemStage) throws Exception {
if(!isAvailable(referenceSystem, systemStage)) return;
Map<String, ReferenceElement> result = new HashMap<>();
try {
Class<?> classTemp = referenceSystem.getClazz();
result = ((ReferenceController) classTemp.newInstance()).searchElements(searchField, searchValues, systemStage);
} catch (Exception e) {
return;
}
if(result != null) orderResults(result, referenceSystem);
}
This question is related to Issue in abstracting common code using function interface and Exception handling in Function interface. Getting idea from those I have written like below:
public void act(Input1 input) throws NonRetriableException, InvalidInputException {
Function<UpdateTaskInput, Boolean> func = item -> {
try {
activityManager.update(item);
return true;
} catch (InterruptedException | JSONException e) {
throw new NonRetriableException(e);
} catch (LockUnavailableException e) {
throw new NonRetriableException(e);
}
};
try {
lockManager.executeWithLock(input.getTaskID(), input, func);
} catch (LockUnavailableException e) {
log.error("{}",e);
throw new NonRetriableException(e);
}
}
and:
public void perform()
throws AutoAllocationException {
Function<UpdateTaskInput, Boolean> func = item -> {
try {
activityManager.allocateTask(item);
return true;
} catch (AutoAllocationException ex) {
log.error("{}",ex);
}
return false;
};
try {
lockManager.executeWithLock(input.getTaskID(), input, func);
} catch (LockUnavailableException e) {
log.error("{}",e);
}
}
executeWithLock() in LockManager is as follows:
#Override
public <T,R> R executeWithLock(String lockName, T input, Function<T,R> func) throws LockUnavailableException {
LockItem lockItem = acquireLock(lockName);
try {
R output = func.apply(input);
return output;
} finally {
releaseLock(lockItem);
}
}
Now the issue with the executeWithLock() function is, it always expects input as an argument, I cannot invoke this for any other function which does not have any input like doStuff().
But I would like to do it using Function interface only with something like following ( so you can see, T is omitted).
#Override
public <R> R executeWithLock(String lockName, Function<R> func) throws LockUnavailableException {
LockItem lockItem = acquireLock(lockName);
try {
R output = func.apply(input);
return output;
} finally {
releaseLock(lockItem);
}
}
Is there any way to do that with Function interface?
You could use a intermediate helper method, which accepts a Supplier<R> but no input. Which then creates a Function<?, R> and delegates to the other method:
public <R> R executeWithLock(String lockName, Supplier<R> supplier) throws LockUnavailableException{
return executeWithLock(
lockName,
null, // input is ignored by our function
ignored -> supplier.get() // this lambda will create Function<?, R> from the Supplier<R>
);
}
This could then be used like this:
executeWithLock("mylock", () -> "Some Value");
Whereas () -> "Some Value" is a Supplier<String>.
If you can't change that code, and thus not be able to add a intermediate helper method. You might just want to pass null as an argument, and then ignore it in the lambda:
executeWithLock("myLock", null, ignored -> doStuff());
You need two methods. The first should take a Supplier rather than a Function and the input. Using Supplier is preferable because it gives you the flexibility to use zero or more input arguments. Using Function means you are limited to one.
You also need a second method which uses Runnable which supports zero or more input arguments and a void return:
public static <R> R executeWithLock(String lockName, Supplier<R> func) {
Lock lockItem = acquireLock(lockName);
try {
return func.get();
} finally {
releaseLock(lockItem);
}
}
public static void executeWithLock(String lockName, Runnable func) {
Lock lockItem = acquireLock(lockName);
try {
func.run();
} finally {
releaseLock(lockItem);
}
}
Sample usage for these example methods:
private static String foo(String input) { return input; }
private static void bar(String input) { }
would look like:
String ret = executeWithLock("lockName", () -> foo("someInput"));
executeWithLock("lockName", () -> bar("someInput")); // void return
Java is able to infer which version of executeWithLock is required based on whether or not there's a return type. If you wanted to be explicit, you could give the methods different names.
Note: this question is more about generics than it is about enums.
I have few enum types, all implementing a common interface IEffect.
For example
enum ElementalEffect implements IEffect {
FIRE, WATER;
}
enum CombatEffect implements IEffect {
PARALYSIS, SLEEP;
}
I would like to parse a config-file, that should add effects to a weapon. For that I have to resolve a given name to one of the effects. To keep it simple to maintain, I thought of writing a method like this (mostly pseudo-code, this does not compile. In fact the point of the question is how to make this compile):
IEffect resolveEffectName(String name, Class... clazzes) {
for(Class clazz : clazzes) {
try {
return Enum.valueOf(clazz, name);
} catch(IllegalArgumentException) { /* ignore, try next class */}
}
throw new IllegalArgumentException("No matching effect found for " + name);
}
// resolveEffectName(readNameFromFile, ElementalEffect.class, CombatEffect.class);
Now the problem I have is that I can't figure out how to write that method without the compiler telling me
The method valueOf(Class<T>, String) in the type Enum is not applicable for the arguments ...
People saying it should be
private static ICombatEffectType getFirstResolved(String name, Class<? extends Enum<?>>... classes) {
for (Class<? extends Enum<?>> clazz : classes) {
try {
return Enum.valueOf(clazz, name);
} catch (IllegalArgumentException e) {
}
}
return null;
}
This is not working. Feel free to try it (if you don't believe me).
The method valueOf(Class<T>, String) in the type Enum is not applicable for the arguments (Class<capture#6-of ? extends Enum<?>>, String)
You can write this fluently, if that's your style:
class FluentGetter {
private final String name;
private IEffect found;
FluentGetter(String name) { this.name = name; }
<T extends Enum<T> & IEffect> FluentGetter search(Class<T> clazz) {
if (found == null) { // If you've already found something, don't overwrite that.
try {
found = Enum.valueOf(clazz, name);
} catch (IllegalArgumentException e) {}
}
return this;
}
IEffect get() {
return found; // + check if it's null, if you want.
}
}
Then:
IEffect effect =
new FluentGetter(name)
.search(ElementalEffect.class)
.search(CombatEffect.class)
.get();
This avoids the problem of the generic bounds on the array of classes by having separate method calls for each.
Pretty sure I wouldn't use this myself; just tossing it out as an option.
What you really want is a map of names to enum constants, which you can easily make using streams:
private static final Map<String, IEffect> constants
= Stream.of(ElementalEffect.values(), CombatEffect.values())
.flatMap(Arrays::stream)
.collect(Collectors.toMap(Enum::name, Function.identity()));
IEffect resolveEffectName(String name) {
if(!constants.containsKey(name))
throw new IllegalArgumentException("No matching effect found for " + name);
return constants.get(name);
}
I found a way to make everything work without warnings using a wrapper class:
private static class Wrapper<T extends Enum<T> & IEffect> {
private Class<T> clazz;
public Wrapper(Class<T> clazz) {
this.clazz = clazz;
}
public IEffect resolveName(String name) {
return Enum.valueOf(clazz, name);
}
}
private static IEffect getFirstResolved(String name, Wrapper<?>... clazzes) {
for (Wrapper<?> clazz : clazzes) {
try {
return clazz.resolveName(name);
} catch (IllegalArgumentException e) {}
}
throw new IllegalArgumentException("No enum has a member " + name);
}
// Example call
ICombatEffectType elemental = getFirstResolved(
type,
new Wrapper<>(ElementalType.class),
new Wrapper<>(StatusEffect.class));
This should compile (with warnings), using your first method:
return (IEffect) Enum.valueOf((Class<Enum>) clazz, name);
I want to be able to use a supertype over different enums, the code consists of three parts:
Manager.search:
public final List<B> search(final Order order, final Field field, final AbstractConstraint... c) throws SearchException {
if (c.length == 0) {
throw new IllegalArgumentException("orm.Manager.search: c.length == 0");
}
try {
List<B> beans = new ArrayList<>();
for (AbstractConstraint constraint : c) {
try (PreparedStatement ps = new QueryBuilder(connection, tableName(), getPaths(), searchQuery()).add(constraint).order(order, field).build();ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
beans.add(createBean(rs));
}
}
}
return beans;
} catch (SQLException ex) {
Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, ex);
throw new SearchException(ex);
}
}
The order and field variables are most important here.
The auto-generated TemplateAttributeField.java:
public enum TemplateAttributeField implements Field {
templateId,
attributeOrder,
attributeName,
x1,
x2;
}
And the calling code:
try (TemplateAttributeManager templateAttributeManager = ManagerFactory.getTemplateAttributeManager()) {
List<TemplateAttributeBean> templateAttributes = null;
try {
templateAttributes = templateAttributeManager.search(Order.ASCENDING, TemplateAttributeField.attributeOrder, new TemplateAttributeConstraint.Builder().templateId(template.getTemplateId()).build());
} catch (SearchException ex) {
Logger.getLogger(OutputProcessor.class.getName()).log(Level.SEVERE, null, ex);
}
for (Word word : words) {
}
}
However at templateAttributes = ... I get the following exception/error:
no suitable method found for search(Order,TemplateAttributeField,TemplateAttributeConstraint)
method Manager.search(Order,Field,AbstractConstraint...) is not applicable
(actual argument TemplateAttributeField cannot be converted to Field by method invocation conversion)
And the Field class is on more than an interface which does not prevent extra functionality.
Am I missing something here, or how should I fix it?
I've tried to create a minimal working example, but it seems to work for me. Could you try if this works for you and is the same as you require?
public class Test {
static interface I {}
static enum E implements I {A}
static void m(I i) {}
public static void main(String[] args) {
m(E.A);
}
}
Also ensure that you implement the same Field interface in your enum as you require in your method. Maybe there's a name clash and you're using interfaces from different packages.