Don't really know if the title fits the problem that I'm trying to solve but here it goes (feel free to modify it for something that makes more sense).
Actually I'm appending String related operations within a Consumer, so that when requested the value is transformed within the chain. However, I see the same exception being thrown in multiple methods and I would like to compress that exact same try/catch clause in an upper level, so that methods only contain the new Consumer definition to be appended.
public static class Clazz {
private Consumer<String> modifications;
public Clazz() {
// ...
}
public void addOp() {
this.modifications = modifications.andThen(item -> {
try {
item.toUpperCase();
} catch (Exception e) {
// logging and exception handling - Merge in common lambda?
}
});
}
public void anotherOp() {
this.modifications = modifications.andThen(item -> {
try {
item.toLowerCase();
} catch (Exception e) {
// logging and exception handling -- Merge in common lambda?
}
});
}
}
Would there be any option to compress all those exception clauses in an upper class? Which is the approach when simplifying lambda try/catch clauses?
Related
I have been working on some methods which perform parallel operations on an LDAP server. My problem is that the method code is basically duplicate except for one line in all methods and I have no idea on how to refactor the methods such that the code would remain relatively readable. There are multiple duplicate methods; I will show two as an example.
Example of the methods:
public static void addEntriesInParallel(LdapConnParams ldapConnParams, List<LDAPEntry> entries) {
ExecutorService executor = Executors.newCachedThreadPool();
CountDownLatch latch = new CountDownLatch(batchCount(entries.size()));
LdapConnParamsBuilder connParamsBuilder = new LdapConnParamsBuilder(ldapConnParams);
for (List<LDAPEntry> entryBatch : Lists.partition(entries, BATCH_SIZE)) {
LdapConnParams threadConnParams = connParamsBuilder.build();
executor.submit(() -> {
try {
LdapTransactions.addEntries(threadConnParams, entryBatch);
latch.countDown();
} catch (LDAPException ex) {
// Exception handling
}
});
}
try {
latch.await();
} catch (InterruptedException ex) {
// Exception handling
}
}
public static void deleteAttributeInParallel(LdapConnParams ldapConnParams, String attribute, List<LDAPEntry> entries) {
ExecutorService executor = Executors.newCachedThreadPool();
CountDownLatch latch = new CountDownLatch(batchCount(entries.size()));
LdapConnParamsBuilder connParamsBuilder = new LdapConnParamsBuilder(ldapConnParams);
for (List<LDAPEntry> entryBatch : Lists.partition(entries, BATCH_SIZE)) {
LdapConnParams threadConnParams = connParamsBuilder.build();
executor.submit(() -> {
try {
LdapTransactions.deleteAttribute(threadConnParams, attribute, entryBatch);
latch.countDown();
} catch (LDAPException ex) {
// Exception handling
}
});
}
try {
latch.await();
} catch (InterruptedException ex) {
// Exception handling
}
}
The only point of difference is the line (first method):
LdapTransactions.addEntries(threadConnParams, entryBatch);
Compared to (second method):
LdapTransactions.deleteAttribute(threadConnParams, attribute, entryBatch);
Now, the problem also is that the methods called within don't match in signatures.
Is there a way to rewrite the code in such a manner that I don't have to keep the same method multiple times with a single line difference?
Thanks for any tips!
You already did most of the work by figuring out what the methods have in common, and what differs.
Now, you only need to extract the common parts into a more general method for executing LDAP jobs, while trying to keep enough flexibility for differences to be supported.
Assuming all functions that you call inside the processing loop take a threadConnParams and entryBatch, and the rest is function-dependent, you could start with this interface:
public static void performInParallel(
LdapConnParams ldapConnParams,
List<LDAPEntry> entries,
LDapAction action)
LDapAction is a functional interface that is meant to be implemented by a lambda (or a concrete class if that's useful) and looks like this:
#FunctionalInterface
interface LDapAction {
void apply(LdapConnParams threadConnParams,
List<LDAPEntry> entryBatch) throws LDAPException;
}
The implementation changes slightly from what you have now, with the main call becoming:
executor.submit(() -> {
try {
action.accept(threadConnParams, entryBatch);
latch.countDown();
} catch (LDAPException ex) {
// Exception handling
}
});
It could look something like this from the API consumer point-of-view:
addEntries:
performInParallel(ldapConnParams, entries,
(threadConnParams, entryBatch) ->
LdapTransactions.addEntries(threadConnParams, entryBatch));
deleteAttribute:
performInParallel(ldapConnParams, entries,
(threadConnParams, entryBatch) ->
LdapTransactions.deleteAttribute(threadConnParams, attribute, entryBatch));
If the performInParallel function requires more input, you can add that to the action interface, but from the code you've provided so far that doesn't seem to be necessary.
I have two APIs (say create and update) that calls the same serviceA. serviceA has a conditional block that will only be called in case of update. serviceA throws a number of different exceptions but some of them will only be thrown within the conditional block called by update I am looking for suggestions for exception handling in my APIs (create and update). What is a recommended practice here? I don't want to have duplicate exception handling logic but if I extract the error handling logic, I might have to catch exceptions that are only applicable to update for create as well.
public class ServiceA {
void upsert(Request request) {
//some common operations for create and update
if (request.action == "UPDATE") {
//update
if (someUpdateErrorCondition) {
throw new ExceptionA();
} elseif (someOtherUpdateErrorCondition) {
throw new ExceptionB();
}
...
}
if (someErrorCondition) {
throw new ExceptionC();
} elseif (someOtherErrorCondition) {
throw new ExceptionD();
}
...
}
Appreciate your help!
Not sure if I correctly understood the problem, but if you have common exceptions to handle as well as specific exceptions then you could use a lambda for common error handling.
There's various flavors of the same approach which is to control the execution with a shared component, whether you use function composition, the decorator pattern, etc.
E.g. (non-java pseudo-code)
function process1() {
withCommonErrorHandling(() => {
try {
//could throw CommonError or Process1Error
} catch (Process1Error e) {
//handle
}
});
}
function process2() {
withCommonErrorHandling(() => {
try {
//could throw CommonError or Process2Error
} catch (Process2Error e) {
//handle
}
});
}
function withCommonErrorHandling(fn) {
try { fn() }
catch (CommonError e) {
//handle
}
}
I have a method. This method has a catch block.
// pseudo code
private void function() {
try {
// something
} catch(exception e) {
// error handling
}
}
This method is called in another class
In one scenario the class is implemented with its own catch block
// pseudo code
private void anotherFunction() {
try {
function();
} catch {
//another catch block
}
Now I just want to execute the code in the catch block where the function is called and don't call the catch block implemented in the class. Is there a way to do this or should I think about another approach?
A workaround is to move your logic to another method which doesn't handle that exception, but just passes it upwards e.g:
public void unsafeFunction() throws Exception{
// something
}
And then call that method from your both classes, where both handle the exception differently:
public void function(){
try {
unsafeFunction();
} catch(Exception e){
// error handling
}
}
And:
public void anotherFunction(){
try {
unsafeFunction();
} catch(Exception e){
// other error handling
}
}
That way you leave what should be done with the exception to the caller.
Another completly different approach is to use the java.util.function.Consumer interface from Java 8 and accept that in your function, the caller then can just pass the error-handler into it:
public void function(Consumer<? super Exception> errorHandler){
try{
// something
} catch(Exception e){
// delegate to handler
errorHandler.accept(e);
}
}
Which can then be used like this:
public void someFunction(){
function(e -> {
// error handling
});
}
And:
public void anotherFunction(){
function(e -> {
// other error handling
});
}
There must be a reason to catch the exception. Say that reason can be tested in a separate method:
private boolean testCircumstanceThrowingException() {
if (exceptionalCircumstance) {
return false;
} else {
return true;
}
}
then you can implement your original function as:
private void functionCatchingException(){
if (testCircumstanceThrowingException()) {
//error handling
}
function();
}
and
private void anotherFunction() {
if (testCircumstanceThrowingException()) {
//error handling
}
function();
}
this way, during the normal running of the application, no exceptions are thrown. And this is how it should be because exceptions are for exceptional circumstances. If you somehow get to a state where exceptions are expected then something is wrong.
You should only rely on excpetions if there is no other way. For instance, if your specific use of the function cannot test the exceptional circumstance and you're required to use function. Take a look at Lino's answer for possible workarounds.
Java purists will notice that you can simply do return exceptionalCircumstance; but this code was just intended to show that a function that tests for the exceptional circumstance may be required; the result may not even be a boolean.
Of course you may now want to rename functionCatchingException :)
In your first code snippet:
private void function() {
try {
// something
}
catch (Exception e) {
// error handling
throw e; // rethrow?
}
}
you basically have two options with Java. You can either swallow the exception, or you can rethrow it. If you swallow it, then the caller of this method won't see an exception. If you rethrow, then the caller would also get an exception.
If neither of these behaviors are what you really want, then you might want to rethink your design.
You can throw the exception to the caller method using the keyword throw:
private void function(){
try{
//something
} catch(Exception e){
//error handling
throw e;
}
}
Then your anotherFunction() catch block will be executed.
You can learn more from here: The Java Tutorials
So I have 20 setters in a row all of which could potentially fail. Rather than skip them all if one fails or surround them each with a try catch is there a way to do this with some of Java 8s features?
For example, I was thinking something like this:
public void mapElement(Function function) {
try the function
catch if something goes wrong
}
Then I could use this like so:
mapElement(myObject.putA(a));
mapElement(myObject.putB(b));
mapElement(myObject.putC(c));
....
How about something like this:
public void tryTo(Runnable action) {
try {
action.run();
} catch (Exception e) {
// do something?
}
}
tryTo(() -> myObject.putA(a));
tryTo(() -> myObject.putB(b));
tryTo(() -> myObject.putC(c));
Note that myObject, a, b and c all need to be effectively final for this to work.
A spin on the above is to have a single method that takes an array of Runnables and executes them in a loop:
public void tryAll(Runnable... actions) {
for (Runnable action : actions) {
try {
action.run();
} catch (Exception e) {
// do something?
}
}
}
tryAll(() -> myObject.putA(a),
() -> myObject.putB(b),
() -> myObject.putC(c));
You could use the Runnable functional interface.
Its function descriptor is () -> void.
It suits perfectly for your need as the mapping operation returns no result and you don't need to specify any parameter as input of the function either.
Indeed here : myObject.putA(a), you don't want to pass the a parameter to the function.
You want rather pass the whole expression myObject.putA(a) as a lambda body :
() -> myObject.putA(a);
You could so write this mapElement() method :
public static void mapElement(Runnable mapProcessor) {
// Retry logic
try {
mapProcessor.run();
} catch (Exception e) {
// exception handling
}
}
Note that to catch any Java exception (both checked and runtime), you have to catch RuntimeException rather than Exception.
And you can use mapElement() in this way :
MyObject myObject = new MyObject();
...
mapElement(() -> myObject.putA(a));
mapElement(() -> myObject.putB(b));
mapElement(() -> myObject.putC(c));
Runnable may not convey the expected meaning as it was primarily
designed for thread execution.
If it makes sense you also may introduce your own functional interface.
With this way, you may also declare any specific checked exception in the function if it appears relevant.
Which is not possible with Runnable.
For example :
#FunctionalInterface
public interface MapProcessor{
void map() throws MappingException;
}
You could so use it in this way :
public static void mapElement(MapProcessor mapProcessor) {
// Retry logic
try {
mapProcessor.map();
}
catch (MappingException e) {
// Mapping exception handling
}
catch (Exception e) { // or RuntimeException if more relevant
// other exception handling
}
}
I have some private method in a class which has equal exception handling. Their body code raises equal exception types and the code handling is the same.
private void method1() {
try {
//make_the_world_a_better_place
}
catch(IOException ioe) {
// ...
}
}
private boolean method2(String str) {
try {
//make_a_cheesecake
}
catch(IOException ioe) {
// ...
}
}
Which is the best way to externalize the common exception handling, so when I make a change in the exception handling code of one of the methods the change will propagate to other methods? Template Method pattern would be handy in this situation, but I don't want go deep into the class hierarchy.
EDIT: There are several catch clauses, not only one like in the example.
Create an interface:
public interface Executor {
void exec() throws Exception;
}
in your class:
checkForExceptions(new Executor() {
#Override
public exex() throws Exception {
method1();
}
});
private void checkForExceptions(Executor ex) {
try {
ex.exec();
} catch (Exception e) [
/// handling
}
Your instinct is good - DRY is a good thing. But don't do this. Your code will be harder to read.
Make sure your catch blocks are really handling the exception and not just swallowing it. If your class isn't providing remediation, I'd say it'd be better to throw it and let clients figure out what to do.
You can create a handleException(IOException ioe) method which they both call.
I was thinking for a try-catch-handling at one place and the method's logic between them, but I guess the world then would be too perfect. Actually I have several catch clauses in the methods.