3

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));
....
Locke
  • 534
  • 8
  • 25
  • 1
    Why do you want to catch the exceptions? Can `mapElement()` safely continue and fulfill its overall contract even if some step failed? Typically, I'd let the exception pass to my caller, unmodified, to let him know that my method failed, and he'll do the same, up to some top-level where exceptions are caught and logged. – Ralf Kleberhoff Nov 01 '17 at 20:46

2 Answers2

10

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));
shmosel
  • 49,289
  • 6
  • 73
  • 138
5

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
  }
}
davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • [FYI](https://stackoverflow.com/questions/27973294/function-with-no-args-and-no-return-type-void-in-java-8?lq=1#comment44339647_27973294) – shmosel Nov 01 '17 at 20:10
  • 2
    @shmosel, yes but declaring a specific exception is not possible with `Runnable`. – davidxxx Nov 01 '17 at 20:15