Should I use Futures.immediateFailedFuture or throw an Exception directly? - java

I need to throw an exception in a AsyncFunction. Guava provides Futures.immediateFailedFuture to do that, but I want to know which is better compared with throwing an exception directly?
ListenableFuture<Void> someFuture;
ListenableFuture<Void> next = Futures.transformAsync(
someFuture,
r -> {
// opt 1
throw new Exception();
// opt 2
return Futures.immediateFailedFuture(new Exception());
}
);

From the docs
Throwing an exception from this method is equivalent to returning a
failing Future.
They are functionally equivalent, so it's only a matter of opinion which is "better". One is clearly more concise than the other.

Related

Why can't checked exceptions in a java stream be thrown at method level?

I've been learning about concurrency and the streams API and came across this. The offerLast()method can throw InterruptedException, so I get that I must handle it. What I don't get is why can't I throw it at the method level by adding throws Exception?. As it is this code does not compile.
static BlockingDeque<Integer> queue = new LinkedBlockingDeque<>();
public static void testing() throws Exception {
IntStream.iterate(1, i -> i+1).limit(5)
.parallel()
.forEach(s -> queue.offerLast(s, 10000, TimeUnit.MILLISECONDS));
}
I know it can be solved by surrounding it in a try/catch, or by creating a wrapper method that handles the error, but I'm still trying to understand why it can't be thrown at the method level.
Because lambda expressions are not always evaluated immediately.
Let's you have this:
public Supplier<String> giveMeASupplier() throws Exception {
return () -> someMethodThatThrowsCheckedException()
}
According to you, the above would work. Right?
Now in another method, I can do this:
Suppler<String> supplier = null;
try {
supplier = giveMeASupplier() // no exception is thrown here.
} catch (Exception ex) {
ex.printStackTrace();
}
if (supplier != null) {
System.out.println(supplier.get()); // this might throw an exception! Yet it's not in a try...catch!
}
Now what do you think would happen if supplier.get() throws an exception? Is there anything to catch it? No. If somehow the catch block a few lines before gets run, then it would be really weird.
The simple answer is that the "method" you're referring to is Consumer.accept, not YourClass.testing.
The lambda s -> queue.offerLast(s, 10000, TimeUnit.MILLISECONDS) is an implementation of java.util.function.Consumer.accept(T), which doesn't declare that it can throw InterruptedException.
And this behavior is not particular to streams, wherever a lambda expression is defined, it must comply with the signature of the abstract method of the functional interface it implements.

Function's return type can be Exception when it throws Exception

Let's say I have a function
private RuntimeException foo() {
return new RuntimeException();
}
and exception there is not thrown and it can be processed like
throw foo();
or return value can be assigned to a variable
RuntimeException e = foo();
But the function can be changed to
private RuntimeException foo() {
throw new RuntimeException();
}
and it still compiles and can be used like in previous examples or can just be called like foo(); and Exception will be thrown.
But why is it possible to specify RuntimeException as a return type of a method that doesn't return it but throws it instead. Is there any connection between throw and return behavior in this case?
I've noticed that having Exception (or more generally Throwable) return type ensures that it will be thrown/returned in every decision branch like if/else statements. But is there any more practical usage or recommended of this?
Since throw will make the execution of the method stop immediately and control is passed back to the caller, it doesn't matter what your method returns. No matter what type you return, that type will not be returned, because you are throwing an exception (which indicates something wrong happened) on the first line.
The compiler allows this because throwing an exception means something wrong happened, like the arguments are invalid, or the argument is null, and so on. In such error conditions, the compiler does not expect the method to return a value normally. It makes sense because obviously when something wrong happens, the method can't compute whatever it is that it was going to compute.
So the phrase "all code paths must return a value" should really say "all code paths must return a value or throw a Throwable".
There is no relation between what a method returns and what it can throw.
and there are use cases where a method may both return and throw an exception.
consider the following scenario: a method that is called to produce an application-specific exception:
public Exception produceException(User u) {
if (u.id == null) return new UserNotFoundException();
if (u.name == null) return new UserDidNotCompleteRegistrationException();
if (u.email == null) return new UserDidNotVerifyEmailException();
}
now guess what will happen if the argument itself is null? and the method does not even declares a throws clause...
now, regarding having Exception as return value for the sake of ensuring that an exception is returned at every branch is just bad design. return value is not the mechanism to be used for throwing exception. if you surround the entire method body with try-catch you will catch all exceptions from all branches.
why is it possible to specify RuntimeException as a return type of a method that doesn't return it but throws it instead. Is there any connection between throw and return behavior in this case?
It's possible to specify any type as a return type of any method. There is no connection between return and throw behavior.
I've noticed that having Exception (or more generally Throwable) return type ensures that it will be thrown/returned in every decision branch like if/else statements
No, that's not the case. There is no way to "ensure [an Exception] will be thrown in every decision branch". The only thing you can do is to state "this method may throw an Exception by using the throws keyword:
public void mightThrowException() throws Exception {...}
but there's no guarantee that any exception will be thrown at all.
BTW, there are two types of exceptions: checked and unchecked. Unchecked exceptions are subclasses of RuntimeException; those do not need to be declared for your method. Checked exceptions do, so
public void throwsIoException() {
throw new IOException();
}
is illegal because IOException is a checked exception that needs to be declared with throws.
You mixed something up with your example. Because when throwing an exception in a method the return type is not really considered, so instead of declaring the method like in your example. you could also declare it like the following:
public void foo(){
throw new RuntimeException();
}
or:
public MyComplexType foo2(){
throw new RuntimeException();
}
The result is simply the same: An exception is thrown. The calling code just will look differently e.g:
foo(); // throws RuntimeException
myOtherComputation(); // is never reached
or
MyComplexType type = foo2(); // throws RuntimeException
type.doSomething(); // is never reached
This behaviour can be useful when using for example a switch statement in a method but throwing an error when entering the default branch:
public String foo(String string){
switch(string){
case "foo":
return "bar";
case "bar":
return "foo";
default:
throw new UnsupportedOperationException("Unknown string: '" + string + "'!");
}
}

Using Java `CompletablyFuture.exceptionally` to optionally continue through exceptions

I have a series of asynchronous tasks chained together using Java CompletableFutures. The code looks something like this:
CompletableFuture<Result> doTasks(final TaskId id) {
return firstTask.workAsync(id)
.thenComposeAsync(__ -> secondTask.workAsync(id))
.thenComposeAsync(__ -> thirdTask.workAsync(id))
.thenApplyAsync(__ -> fourthTask.workAsync(id));
}
However, firstTask.workAsync throws an exception indicating that the work has already been completed, which is OK in this situation, so I would like to just ignore it and continue through the chain.
Of course, I could just wrap that bit in a separate function where I can handle the exception, but is there a way to handle it directly in the CompletableFuture chain and continue to throw all other exceptions?
A co-worker suggested I use CompletableFuture.exceptionally, but all of the examples online that I see are totally useless and just return null, which looks like it would kill the chain. How would I use that in this case?
CompletableFuture.exceptionally can be used to continue when getting an exception in a CompletableFuture. In a nutshell, you need to check the type of the exception, and if it's an exception you want to continue on, you can return a new CompletableFuture, which can be empty since the result is not used down the chain.
CompletableFuture<Result> doTasks(final TaskId id) {
return firstTask.workAsync(id)
.exceptionally(t -> {
// Will continue down the chain if matches
if (t instanceof TotallyOkException) {
return null;
}
// This will throw an ExecutionException. I convert it to a RuntimeException here
// because I don't want to add throws statements up the chain.
throw new RuntimeException(t);
})
.thenComposeAsync(__ -> secondTask.workAsync(id))
.thenComposeAsync(__ -> thirdTask.workAsync(id))
.thenApplyAsync(__ -> fourthTask.workAsync(id));
}
In this case, it will throw all non-TotallyOkException exceptions.
Returning null in your exceptionally function will not, in itself, kill the chain. The only way it will kill the chain is a result of lack of null handling in the downstream function and causing a NullPointerException.
Your exceptionally function can be set up to handle some types of exception and not others. For example:
return firstTask.workAsync(id)
.thenComposeAsync(firstResult -> secondTask.workAsync(id))
.exceptionally(t -> {
if (t instanceof TransientException) {
return getUsingBackupMethod(id);
}
throw new RuntimeException(t);
});
This exceptionally function will (effectively) catch an exception thrown from either of the first two tasks.

Explain what this fail() method does in this junit test

I am having a bit of trouble understanding with the fail() method for JUnit tests does in practice. I looked around online and saw from the junit website that fail(java.lang.String message) "Fails a test with the given message." In the JUnit test I'm looking at, this is the following code:
#Test (expected = RuntimeException.class)
public void testBadCombine(){
AvocadoPortion ap1 = new AvocadoPortion(amount1);
AvocadoPortion ap2 = new AvocadoPortion(amount2);
IngredientPortion ap3 = ap1.combine(ap2);
CrabPortion cp1= new CrabPortion(2);
ap1.combine(cp1);
fail("Expected RuntimeException to be thrown");
}
Can someone please explain what the (expected = RuntimeException.class) does?
And if a RuntimeException IS thrown, does the fail("Expected RuntimeException to be thrown"); line not get executed, making the JUnit test succeed?
Why is the ap.1combine(cp1); line not under a try and catch block? (When do you need to use a try and catch block?)
As you can see I'm pretty confused and could use some clarification
The reasonable options to make that testing code more clear:
A) just use expected
#Test (expected = RuntimeException.class)
public void testBadCombine(){
AvocadoPortion ap1 = new AvocadoPortion(amount1);
AvocadoPortion ap2 = new AvocadoPortion(amount2);
IngredientPortion ap3 = ap1.combine(ap2);
CrabPortion cp1= new CrabPortion(2);
ap1.combine(cp1);
}
B) If required, do some specific testing on your exception ...
#Test
public void testBadCombine(){
AvocadoPortion ap1 = new AvocadoPortion(amount1);
AvocadoPortion ap2 = new AvocadoPortion(amount2);
IngredientPortion ap3 = ap1.combine(ap2);
CrabPortion cp1= new CrabPortion(2);
try {
ap1.combine(cp1);
fail("should have thrown");
} catch (TheExactExceptionYouExpect e) {
assertThat(e.getSomeProperty(), is(whatever));
}
}
You would prefer option "A)" - you only turn to "B") when in fact you want to assert certain properties of that exception thrown by the code under test.
Can someone please explain what the (expected = RuntimeException.class) does?
It requires the test to throw a RuntimeException in order to pass.
And if a RuntimeException IS thrown, does the fail("Expected RuntimeException to be thrown"); line not get executed, making the JUnit test succeed?
Exactly. This is technically redundant because of the expected element above. The only difference is that any Throwable would pass this check, but not the previous one.
Why is the ap.1combine(cp1); line not under a try and catch block? (When do you need to use a try and catch block?)
Try/catch is normally used for gracefully handling an exceptional situation. In other words, if an issue comes up, we want to solve it or work around it and then proceed normally. Here, we take the opposite approach and propagate the exception instead of handling it, so JUnit can know the exception was thrown.
You are correct, it is redundant to have both the expected and the fail(). One of them would be enough and hence appropriate.
For most exception types, you are also correct that if you want to use fail() rather than expected, you would use a try-catch statement with fail() in the end of the try part. In this respect, RuntimeException is special since it is the parent exception of all unchecked exceptions. Since no statement in the method can throw any checked exceptions, we know that either an unchecked exception is thrown, that is, a RuntimeException, or the method will reach the call to fail(). One or the other, not both.

Exception Classes in Java

Exception Handling: Direct quote from a professor, "Although the Exception class can be used directly in a program, it is better to use a specific exception class." He did not extend much on it but I am interested in knowing what others think and if he is right, why?
Your professor probably meant that it is better to throw SomeTypeException than to throw Exception with some text message.
Why is it better to use a typed exception?
You can catch exceptions of specific types.
try {
...
} catch(ExceptionType1 e) {
...
} catch(ExceptionType2 e) {
...
}
Types of exceptions thrown by a method give valuable information to the programmer about the method.
void someMethod() throws SQLException, ParserException { ... }
is more meaningful than:
void someMethod() throws Exception { ... }
What he means is that nothing prevents you from doing throw new Exception( "this happened" ); and throw new Exception( "that happened" );
But it is best practice to do throw new ThisException() and throw new ThatException();
That's because elsewhere you can catch( ThisException e ) and handle it, knowing precisely what happened, without having to catch( Exception e ) and wonder whether it was thrown because "this" happened, or because "that" happened.
I have been in situations where I had to do String s = e.getMessage(); and then try to parse the string to try and make sense out of it, and believe me, it is not fun at all having to do stuff like that.
My two cents:
Exceptions, as any other part of an API, should be as specific as possible. It's the same reason why you should use specific types as String, Integer or Date instead of plain Objects.

Categories

Resources