Using exceptions with Google Guava - java

What is the best pattern for using Google Guava with methods that should throw exceptions?
Let's say I have:
public Sting someMethod(Integer i) throws SomeException;
And I want to do:
List<String> s=Lists.transform(is,new Function<String, Integer>() {
public String apply(Integer i) {
return someMethod(i);
}
});
I couldn't do the above because of the exception. Is there any nice pattern for handling it?

Propagate the checked exception as a RuntimeException:
try {
return someMethod(i);
} catch (SomeException e) {
throw new RuntimeException(e);
}
EDIT: Since the transformed list is lazily evaluated, the exception won't be thrown until you access the list elements. You can force the evaluation by copying the transformed list into a new list, like:
s = new ArrayList<>(s);
You could wrap that in a try-catch block that catches RuntimeException and handles it however you want; your original SomeException instance can be obtained by calling getCause() on the RuntimeException. Or you could just let the RuntimeException bubble up.

You can use
public interface FunctionWithException<T, R, E extends Exception> {
public R apply(T t) throws E;
}

It depends on how you want to handle the exception.
Stop the list transformation when an exception occurs: See #dnault's answer.
Continue the list transformation and remove the element which caused exception (and log some error message).
In this case, we will return null when an exception occurs, this null value will be removed from final list:
List<String> s = Lists.newArrayList(
Iterables.filter(
Iterables.transform(l, new Function<Integer, String>() {
#Override
public String apply(Integer i) {
try {
return someMethod(i);
} catch (SomeException e) {
e.printStackTrace();
return null;
}
}
}), Predicates.notNull()))`
EDIT
If someMethod can return null value then you should a wrapper like this one:
class Wrapper {
public Exception exception = null;
public String result = null;
}
The list transformation will then be:
List<Wrapper> wrappers = Lists.newArrayList(
Iterables.filter(
Iterables.transform(l, new Function<Integer, Wrapper>() {
#Override
public Wrapper apply(Integer i) {
Wrapper wrapper = new Wrapper();
try {
wrapper.result = someMethod(i);
} catch (SomeException e) {
wrapper.exception = e;
}
return wrapper;
}
}), new Predicate<Wrapper>() {
#Override
public boolean apply(Wrapper wrapper) {
return wrapper.exception == null;
}
}));

Related

How to catch exceptions within Java 8 Stream.flatMap(..)

Given a Stream and a method that returns a Stream for different arguments as data source, I'm looking for a way to merge the streams via flatMap(..) and catching certain Exceptions during the execution.
Let's take the following code snippet:
public class FlatMap {
public static void main(final String[] args) {
long count;
// this might throw an exception
count = Stream.of(0.2, 0.5, 0.99).flatMap(chance -> getGenerator(chance, 20)).count();
// trying to catch the exception in flatMap() will not work
count = Stream.of(0.2, 0.5, 0.99).flatMap(chance -> {
try {
return getGenerator(chance, 20);
} catch (final NullPointerException e) {
return Stream.empty();
}
}).count();
System.out.println(count);
}
// !! we cannot change this method, we simply get a Stream
static Stream<Object> getGenerator(final double chance, final long limit) {
return Stream.generate(() -> {
if (Math.random() < chance) return new Object();
throw new NullPointerException();
}).limit(limit);
}
}
Is there any way to catch the exception of each individual Stream that was created by getGenerator(..) and simply suppress the Exception, replacing the "corrupted" Stream with an empty one or skip those elements from the specific generator Stream?
It is possible to wrap the Stream into another using the Spliterator. This method will protect a given Stream by catching the Exception and saving this state:
static <T> Stream<T> protect(final Stream<T> stream) {
final Spliterator<T> spliterator = stream.spliterator();
return StreamSupport.stream(
new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE,
spliterator.characteristics() & ~Spliterator.SIZED) {
private boolean corrupted = false;
#Override
public boolean tryAdvance(final Consumer<? super T> action) {
if (!corrupted) try {
return spliterator.tryAdvance(action);
} catch (final Exception e) {
// we suppress this one, stream ends here
corrupted = true;
}
return false;
}
}, false);
}
Then we can wrap our Stream method and safely pass it in flatMap(..):
// we protect the stream by a wrapper Stream
count = Stream.of(0.2, 0.5, 0.99)
.flatMap(chance -> protect(getGenerator(chance, 20)))
.count();
One work around is to force the Stream created by getGenerator to be evaluated within the flatMap method implementation. This forces the NullPointerException to be thrown within the try-catch block, and therefore, able to be handled.
To do this, you can collect the Stream (to a List for example):
getGenerator(chance, 20).collect(Collectors.toList()).stream()
Incorporating this into your original snippet:
public class FlatMap {
public static void main(final String[] args) {
long count;
// trying to catch the exception in flatMap() will not work
count = Stream.of(0.2, 0.5, 0.99)
.flatMap(chance -> {
try {
return getGenerator(chance, 20).collect(Collectors.toList()).stream();
}
catch (final NullPointerException e) {
return Stream.empty();
}
})
.count();
System.out.println(count);
}
// !! we cannot change this method, we simply get a Stream
static Stream<Object> getGenerator(final double chance, final long limit) {
return Stream.generate(() -> {
if (Math.random() < chance) return new Object();
throw new NullPointerException();
}).limit(limit);
}
}
Warning: this approach may reduce performance if the getGenerator Stream would be better to evaluate lazily.
Try this:
static <T> Supplier<T> getOrNull(Supplier<T> supplier) {
return () -> {
try {
return supplier.get();
} catch (Throwable e) {
return null;
}
};
}
static Stream<Object> getGenerator(final double chance, final long limit) {
return Stream.generate(
getOrNull(
() -> {
if (Math.random() < chance) return new Object();
throw new NullPointerException();
// You can throw any exception here
}))
.limit(limit)
.filter(Objects::isNull);
}
Then simply call getGenerator:
count = Stream.of(0.2, 0.5, 0.99)
.flatMap(chance -> getGenerator(chance, 20))
.count();

Java Lambda Exception Handling

I have a problem with the handling of exceptions, without the use of try and catch, in lambdas.
I found example code for which I need to make my own Consumer interface, but it doesn't work and I don't know how to fix it.
import java.util.function.Consumer;
#FunctionalInterface
public interface ThrowingConsumer<T, E extends Exception> {
void accept(T t) throws E;
static <T> Consumer<T> throwingConsumerWrapper(
ThrowingConsumer<T, Exception> throwingConsumer) {
return i -> {
try {
throwingConsumer.accept(i);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
};
}
}
Here is the lambda in which I need to handle IOException. This exception must be thrown from main. I do not wish to use try and catch in main.
public static void main(String[] args) throws IOException {
Function<String, List<String>> flines = fileName -> {
Scanner scanner;
ArrayList<String> wiersze = new ArrayList<>();
File f = new File(fileName);
scanner = new Scanner(f); // here :(
while (scanner.hasNext()) {
wiersze.add(scanner.nextLine());
}
scanner.close();
return wiersze;
};
}
I am new to Java, so please could you explain to me how to fix this problem in the easiest way.
So is your problem that you have a piece of code that throws a checked exception, and you want that to become the implementation of a Function object? You've found somewhere how to do it for Consumer, you just need the code adapter for Function?
Assuming that the rewrite should look something like:
import java.util.function.Function;
#FunctionalInterface
public interface ThrowingFunction<T, R, EXC extends Exception> {
R apply(T t) throws EXC;
static <T> Function<T> throwingFunctionWrapper(
ThrowingFunction<T, R, Exception> throwingFunction
) {
return t -> {
try {
return throwingFunction.apply(t);
} catch (Exception exc) {
throw new RuntimeException(exc);
}
};
}
}
To be a little more general, throwingFunctionWrapper could be:
static <T> Function<T> throwingFunctionWrapper(
ThrowingFunction<T, R, ? extends Exception> throwingFunction
) {
In order to deal with the exception you should subclass RuntimeException and then only catch that class, so as to not unwrap any other runtime exceptions.
Unwrap (with the original code) as:
try {
...
} catch (RuntimeException exc) { // subclass me !!
throw (IOException)exc.getCause();
}

How do I handle exceptions in map() in an Observable in RxJava

I want to do this:
Observable.just(bitmap)
.map(new Func1<Bitmap, File>() {
#Override
public File call(Bitmap photoBitmap) {
//File creation throws IOException,
//I just want it to hit the onError() inside subscribe()
File photoFile = new File(App.getAppContext().getCacheDir(), "userprofilepic_temp.jpg");
if(photoFile.isFile()) {//delete the file first if it exists otherwise the new file won't be created
photoFile.delete();
}
photoFile.createNewFile(); //saves the file in the cache dir
FileOutputStream fos = new FileOutputStream(photoFile);
photoBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);//jpeg format
fos.close();
return photoFile;
}
})
.subscribe(//continue implementation...);
Basically in the call() method, it can throw exceptions. How can I make the Observer handle it in onError(). Or is this not the right way to think about this?
rx will always catch error, even if this is RuntimeException.
So you can throw Some kind of Runtime exception in catch block. This is how actually it should work.
Observable.just(bitmap)
.map(b -> {
try {
// do some work which throws IOException
throw new IOException("something went wrong");
} catch (IOException e) {
throw new RXIOException(e);
// Or you can use
throw Exceptions.propagate(e);
// This helper method will wrap your exception with runtime one
}
}).subscribe(o -> {
// do something here
}, exception -> exception.printStackTrace());
public static class RXIOException extends RuntimeException {
public RXIOException(IOException throwable) {
super(throwable);
}
}
With 1.0.15, there is the fromCallable factory method which let's you run a Callable instance for each subscriber where you can throw checked exceptions as well:
Observable.fromCallable(() -> {
File photoFile = new File(App.getAppContext().getCacheDir(),
"userprofilepic_temp.jpg");
if (photoFile.isFile()) {
//delete the file if it exists otherwise the new file won't be created
photoFile.delete();
}
photoFile.createNewFile(); //saves the file in the cache dir
FileOutputStream fos = new FileOutputStream(photoFile);
photoBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);//jpeg format
fos.close();
return photoFile;
})
.subscribe(...)
Edit:
source.flatMap(v -> {
try {
//...
return Observable.just(result);
} catch (Exception e) {
return Observable.error(e);
}
})
.subscribe(...);
Just created helper class to extract this boilerplate to another place:
public class RxRethrow {
public static <T, R> Func1<T, R> rethrow(Func1R<T, R> catchedFunc) {
return t -> {
try {
return catchedFunc.call(t);
} catch (Exception e) {
throw Exceptions.propagate(e);
}
};
}
public interface Func1R<T, R> extends Function {
R call(T t) throws Exception;
}
}
You can call it like this:
.map(RxRethrow.rethrow(products -> mapper.writer(schema).writeValueAsString(products)))
I don't know how the situation was when this question was first asked and answered, but RxJava currently contains a helper-method for this exact purpose:
Exceptions.propagate(Throwable t)
RxJava Javadoc
Convenience method to throw a RuntimeException and Error directly or wrap any other exception type into a RuntimeException.

How do I write lambda expression which rethrows checked exception without using try {} catch {} block?

I have a lambda expression, which can throw a IOException:
Function<String, List<String>> readFile = path-> {
try {
return Files.readAllLines(
Paths.get((String) path), Charset.forName("UTF-8"));
} catch (IOException e) {
return null;
}
};
I would like to write the same lambda expression without using the try {} catch {} block, so that the exception would be rethrown to the enclosing function:
public static void main(String[] args) throws IOException {
Function<String, List<String>> readFile = path-> {
try {
return Files.readAllLines(
Paths.get((String) path), Charset.forName("UTF-8"));
} catch (IOException e) {
return null;
}
};
}
The only problem is that I cannot define my own interfaces/classes and I can only use interfaces provided by Java APIs.
Would that be possible?
If you want to rethrow the excepion, you can use RuntimeException.
Add this to your catch body.
throw new RuntimeException(e);
Since Function.apply does not throw checked exceptions, you cannot do it ...
... in a legal way. However, you can consider "sneaky throw" if you can take the risk
interface FunctionX<T,R, X extends Exception> extends Function<T,R>
{
R applyX(T t) throws X;
#Override
default R apply(T t)
{
try
{
return applyX(t);
}
catch (Exception x)
{
throw Util.sneakyThrow(x);
}
}
public static <T,R,X extends Exception>
FunctionX<T,R,X> of(FunctionX<T,R,X> f){ return f; }
}
// Util.java
public static RuntimeException sneakyThrow(Throwable t)
{
throw Util.<RuntimeException>sneakyThrow0(t);
}
#SuppressWarnings("unchecked")
private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T
{
throw (T)t;
}
Usage example
Function<String, List<String>> readFile = FunctionX.of( path-> {
return Files.readAllLines(
Paths.get(path), Charset.forName("UTF-8"));
} );
readFile.apply("/no-file");

Catch Exception from Method Reference

I’m trying to pass a method reference which throws a checked Exception:
Files.list((Paths.get("/some/path"))).map(Files::readAllLines);
How can I handle this exception (without wrapping the method reference in a method which handles the exeption).
If you're attempting to catch an exception for a specific value in the .map I wouldn't recommend a method reference, instead use a lambda:
Files.list((Paths.get("/some/path"))).map((someVal) -> {
try {
//do work with 'someVal'
} catch (YourException ex) {
//handle error
}
});
If you want to rethrow the exception after, you can do so manually with a reference to the error through a box:
//using the exception itself
final Box<YourException> e = new Box<>();
Files.list((Paths.get("/some/path"))).map((someVal) -> {
try {
//do work with 'someVal'
} catch (YourException ex) {
//handle error
e.setVar(ex);
}
});
if (e.getVar() != null) {
throw e.getVar();
}
class Box<T> {
private T var;
public void setVar(T var) { this.var = var; }
public T getVar() { return this.var; }
}

Categories

Resources