Java 8 Lambda Basics 18 - An Exception Handling Approach

preview_player
Показать описание

This video proposes an alternative way of handling exceptions in lambdas. In the process we'll also learn how to wrap lambda expressions in other lambda expressions!
Рекомендации по теме
Комментарии
Автор

I've been through a bootcamp, had coaches with accumulated 40 years of java experience and looked through many other resources. I have to say I have never enjoyed tutorials as much as I enjoy your stuff. You really made me become a better developer. This is gold, thanks a lot Sir.

Japhu
Автор

my brain started throwing exception while i was trying to understand this lambda way of exception handling :)

humaripragati
Автор

Thanks for the video.
For ppl who have difficulty to understand the code:
Remember that, we have two BiConsumer here. One is passed to the wapperLambda by main method. Another one is created by wapperLambda as a return object.
and 2nd BiConsumer that returned by wapperLambda is nothing but a accept(k, v) that rapped in a try-catch block. Note that, it is here in wapperLambda, the accept(k, v)'s body has been set to System.out.println(k/v).
So at the end, what process method doing is, executing 2nd BiConsumer which has both try-catch block and println in it.
If you still couldn't get the idea, go to your IDE, make some stop points and run in debug mode. so you can see how code jumps around.

AlexAkira-ydnk
Автор

I watched this video atleast 10 times to understand how the wrapper method is created. One of the best tutorials on Lambda I have seen on you tube.
Hats Off to this guy. Explained everything in evolutionary way. Just Brilliant...

mailgauravat
Автор

Thank you very much, its quite hard concept to understand for me watched probably 10 times form 4:40, i think i understood eventually. thank you very much.

TheGuroguro
Автор

Thank you! Best tutorial. I wrote the following simple Generic wrapper:

import java.util.Arrays;
import java.util.List;
import

public class LambdaExample{

public static void main(String[] args){
List<Integer> numbers = Arrays.asList(2, 3, 7, 10, 9, 1, 110);
int key = 1;
process(numbers, key, wrapperConsumer((Integer i, Integer j)-> System.out.println(i/j), ArithmeticException.class));

}

private static <T> void process(List<T> values, T key, BiConsumer<T, T> consumer){
values.forEach(i->consumer.accept(i, key));
}

private static <T, E extends Exception> BiConsumer<T, T> wrapperConsumer(BiConsumer<T, T> consumer, Class<E> exClass){
return (i, j) -> {
try{
consumer.accept(i, j);
}catch(Exception e){
E clazz = exClass.cast(e);
System.err.println( "Exception Message: " + clazz .getMessage());
}
};
}
}

Amanuelalemayehu
Автор

whenever i come across a video of this channel i put like straight away because i know the video will be good

olenaqwerty
Автор

What a convoluted way of doing something so simple. Not a criticism of the instructor but rather of Java, so I will leave it at that.

nml
Автор

A solution, that would be more elegant is to use a distinct class for the wrapper. Using a class will allow to store the exception caught and to react on it at the call-site.

Here is how this works:

1. Separate the two concerns (computation and printing), that are in the current lambda:

// ....
process(someNumbers, key, (v, k) -> print(v / k));

}

private static void print(Object value) {
System.out.println(value);
}

Ok. That alone won't help for sure ;)


2. Create a wrapper-class

class Try implements BiConsumer<Integer, Integer> {
private Consumer<Exception> onException = null;
private Consumer<Object> next;
private BiFunction<Integer, Integer, Object> action;

public Try(BiFunction<Integer, Integer, Object> action) {
this.action = action;
}

@Override
private void accept(Integer a, Integer b) {
try {
next.apply(action.accept(a, b));
} catch (Exception e) {
if (onException != null) {
onException.accept(e);
}
}
}

public Try ifPresent(Consumer<Object> consumer) {
this.next = consumer;
return this;
}

public Try onException) {
this.oneException = onException;
return this;
}
}

And use that in the main-method like this:


process(someNumbers, key, new Try((v, k) -> v / k)
.peekException(ex -> System.out.println("an exception occured"))



The implementation above may look a bit weird at first glance: It uses an approach like a builder (the "return this" stuff allows to chain calls). I've chosen this style, so it looks more familiar to what
many functional programmers use. I still kept it a bit simpler for now, though.

Please note the following properties from the view of the main-method:

* The two concerns (computation and printing) are split into two lambdas
* You have "full access" to the exception, but you don't need to handle it
* Rather than being thrown, the exception is passed around as a variable now


3. The final thing

What functional programmers use is called a "Try-Monad". This Monad will wrap a value (or the exception) somehow like Optional would wrap a value in Java.
In functional languages you typically don't throw exceptions but rather handle it as a possible outcom
e of a function-call (i.e. in its return-value).

Trying to write it functionally, but still using Java-sytax the end-result might look somewhat like this (using a different implementation of Try than outlined above):

Try result = new Try(myData)
.map(data -> computation1(data))
.flatMap(data -> computation2(data))
.map(data -> computation3(data));
if (result.isExceptional()) {

} else {

}

In this example "computation1" is a function, that simply transforms the data (but cannot create an exception). However, "computation2" is a function that returns an instance of Try itself. Should there b
e an exception in the result of "computation2", it would get carried over into the "Try result =.." an
d "computation3" would never get executed.

tobias
Автор

Hi @Kaushik .. Thanks a lot for adding Lambda Videos. I got very good knowledge on lambdas now :)
I am very grateful to you :)

amith
Автор

I've done this kind of Exception handling in Javascript and PHP, but I didn't know how to do it in Java. Thank you very much.

It is also possible to make wrapperLambda to receive a second parameter, a Functional Interface, to handle the Exception. For instance, to log the Exception in the console, pass a Consumer<Exception> to wrapperLambda as a second argument

ratias
Автор

My brain stopped braining after 4:30 and I think it is time to take a break or a whole day off to recover and try again to understand.
But Hey kaushik I have been following your channel and it is always a pleasure to watch your videos on topics, they are clear and its like you are taking me up on a (staircase = s -> s.getTopicName()) and without missing a single step you bring us to the top and there I get a feeling that I saw, understood and now I know every component of a staircase such that I can even build one for my house.

tarunsoni
Автор

Best tutorial hands down Interface iF = () -> System.out.println("Thank You Sir")....Please do a JUNIT video tutorial too.

eugenembanda
Автор

One thing to note is execution is happening from outside to inside, I mean first process function gets wrapper lambda and then process method execute inside lambda BTY, Good work! @javaBrains

hanmantlokare
Автор

For the approach where you added try-catch block inside the for loop you were right. We actually may not know the operation happening by the lambda expression.

Well, your final solution to have a wrapper lambda handling the exception with try catch is again heading to the same problem! We may still not know the operation happening.

I felt original lambda handling the exception is a better approach.

ShahPreet
Автор

Best thing we can do is put try catch in first lamda itself and put catch as Exception.And print System.ou.println(e) or e.printStackTrace(). It worked for me, hope it works for others also.
private static void process(int[] someNumbers, int key, BiConsumer<Integer, Integer> consumer) {
for (int i : someNumbers) {
try {
consumer.accept(i, key);
} catch (Exception e) {
System.out.println(e);
//or
e.printStackTrace();
}
}
}

nehalhyder
Автор

It might have been a good idea, to include a Zero in the somenumber array, let key always be > 0 but calculate k/v, so that only one operation would trigger the exception.

unbekannter_Nutzer
Автор

Thank you again for your nice tutorial. I have a couple of qs, could you pls clarify.

1. Since we are associating the exception with the lambda functionality, when the functionality is called in a loop, it executes the exception number of times. Can we restrict that anyway?

2. While creating a wrapper again we have to be concerned about the types of exception the functionality might throw if we want it to be generic and that again will require multiple catch blocks, else for specific functionality we need customized wrappers that again will lead us to write multiple of them based on the application.

Though I understand this way we can nicely segregate the exceptions form the business logic, still feel it might add some extra overhead as well.

If we catch the exception where we call the process method...
try {
process(sumNumbers, 0, (num, k) -> System.out.print(num / k));
} catch (ArithmeticException e) {
System.out.println("Dividing by zero");
}
-- here we right away know what exception the functionality might throw and handle it.
Any suggestion?

taniakhan
Автор

This approach holds true in case of runtime exceptions. But this does not work for checked exceptions. I faced this issue while coding for work. Need to reach out to the internet to see how this could be handled.

MrRahulKumarKandula
Автор

I understand adding a wrapper function will help us to have a more clear function but at the same time, we are adding more instructions right? I would rather choose handling the expectation while we call the lambda function rather than writing a wrapper

YemaneHadis
join shbcf.ru