 Well, let's get started. Good evening and welcome to the session on functional fluency in Java. Well, before I get started, how many are familiar with streams and lambdas? Almost all. Okay, so while Java 8 introduced, you know, lambdas at streams, which helped us to do functional programming in Java. Maybe Java was one of the last languages to support programming. Once we started using that, I mean, it provides a good start, but soon we will start hitting the limit of functional programming and we see certain gaps. So in this session, I'm trying to address how we can do more fluent functional programming in Java. And in this case, I mean, there are many people have tried to build this gap by writing their own libraries. And in fact, there is one good library that is kind of fulfills most of the gaps which was called Java slang in the beginning. But since the word Java was a trademark belongs to Oracle, people decided to change the name. But somehow people didn't want to, didn't want to fit in the sticker. So that's why they just turned the Java around and got the AVR waiver. So they could use their laptop sticker. That's how they got into this name. So mostly I'm going to use the functionalities provided by this library to show you the part to demonstrate more fluent functional programming. So without delay, let's get started. Okay, I hope people are able to follow this code. So we have a predicate even with checks whether a number is given and I have a function which doubles given number. And as a data, I'm starting with the list here and I'm going to get, you know, this map filter reduce. I have to create a stream out of my list. That's why I use numbers.stream because, you know, they couldn't change the earlier interfaces. That's why they have to use stream. And once your processing pipeline is over, you want to collect it back to list using the collect. And you run this, you will get all the numbers multiplied by 2. That is 4, 8, 12. By the way, feel free to ask any questions. So obviously you would see I had to do something, the stream, which is totally, you know, a noise here, although I don't have any real benefit of doing that. There's no real need for that. But it's more of for that. We have to agree to Java's field for doing things, which should have been under the roof by me. And we have to convert it back back. So the first thing that comes in the way of writing a fluent function program. So let's see how we could use a waiver library and get this done. So I have written the predicate. By the way, Java provides a function and by function. So if you want anything, the function which accept more than two arguments, you'll have to write your own functional interfaces, which waiver avoids. So instead of, you know, in this case, I want a function which accepts one argument and return one. So I could use function one provided by your waiver. You have right from function zero to function eight, which could be used. So I have that. So let me create with the list data. So I don't have to do all those ceremony here. I could write away, you know, create list. I want, yeah, from the collection. We want to do five. So I got a list. So Java did add something of this list.of in Java nine, kind of creates a mutable collection. But it comes with a lot of if you could with the documentation. Yeah, so let's get started with this list. And right away, I want to, you know, filter. So I can say filter all the given numbers. And then what I want is to map, which is the doubler. Then I can say for each, I can just print. So you're just focusing on what you need. So couple of things to notice. We already talked about function. So the list, what I used here comes from the waiver library, which is in the process collection. So, you know, whatever immutable benefit you want to take advantage of, that's available to you right away. Having said that, if it doesn't implement Java, you can collection Java, you can list. There are certain convenient function which will help you to say from here, you can say to Java list, to Java map, to Java send, all of that. You have other, I'll come to that. Yeah, so you can use the advantage of those functions and convert back to Java collections and, you know, use it in the code that you have already written. So the next thing, let's go back to the here. And one good thing about Java streams is that it's indeed lazy, so I could just say, instead of select, I could just do find first, in this case, let me directly do get, even though there's a possibility that the value will not be present. But in this case, at least I know that. So let me just put a p and filter, you can see. All I wanted was for, you know, it was lazy and it didn't practice all the elements. So this property is maintained by here also. We will get to see more of those. So let's do a few things here. Say I already have numbers.stream. Say I want to use, I want to perform a different set of operations on the same set of data. So I think I already have a number. I have a stream. Why not reuse this stream here? Why not take the stream out? Works fine. So now let me say stream.forEach and let's say just want to print this. So what is going to happen? That's an interesting exception. It says that stream has already been operated upon or closed. So that means that you cannot reuse that stream after a set of operation. You'll have to throw it away. You'll have to create a new stream from that because under the hood, the stream is just a kind of decorated iterator which maintains state. So let's try to do this here in the waiver version of the code. And I can also create stream directly using stream.off like this. Let's say it's a stream.off integer. And let me try to reuse that. So I say numbers.forEach. I could, you know, the first one was 48. Then I could print the number from 105. So you could reuse the stream. So that's one. So now if I just try to print the stream as such, which is a stream of this process here, but the stream is actually... It's easy. By default, you have the first element, which is the head, and the rest of the elements are not processed. So as required, we'll go ahead and process it. With that, let's get into solving the business problem. People are aware of business. So this is how the, you know, every third word is a phase. Every fifth word is a bus. So, you know, the 15th word would be phase bus. And others, you'll have to see the numbers, the sequence. So I would have 1, 2, phase, 4, bus, phase 7, 8, phase bus, like that. I mean, you need a lot of code if you're going for imperative style, but you could use Java 8 streams and get it to some extent. But one of the interesting ways of solving this problem is using infinite streams or infinite sequence. So, you know, every third word is a phase. So how can I model that? I can say stream of first word is empty, second word is empty, and third word is phase. So I want to repeat this infinitely. I don't know how many I want. Java 8 stream doesn't provide anything while waver stream does provide a function called cycle. So I can use this. So now I got phase. Similarly, I can create a bus. First word is blank, second is blank, third is blank. Just I have bus, and I would cycle it. Again, I would get an infinite stream of bus. What can I do now? How can I combine phase and bus? Any thoughts? Yeah, zip. Zip works quite, you know, in an excellent way if you're using the Haskell, but here I'll just have to use two at a time. So I cannot use that number sequence also along with this. So I'll have to do two at a time and then combine with the third. So let's try to do that. So phase and let me say zip, and let me try to put first here. So put it into a variable called phase bus. And let's try to print dot. Zip works dot. Take 10 and 40. Yeah, sorry. It should be phase bus. Okay. So it created, as you could see in the signature here, it created a stream of triple two string and string. So in the first position, you'll have the phase sequence from the phase stream and second word, you'll have the word or string from the bus stream and by default, it created a couple. But I would want, you know, phase bus. If it comes together, I want phase bus. So essentially what I want is a single value. What I can do is I can, you know, instead of using zip, I can say zip width. With the buzz of course. And now I can say how I can combine these, you know, to have left and right here. What I need is the, you know, left concatenated with the right. Right. First word plus second word. That's now call it as phase bus. And now you see that you got 15 should be phase bus. So now we want to zip with the, the, the, you know, numbers. Right. Want to visit. Come like that. How would I do that? So you see I have a zip with the index here. So here I put the, you know, pass a function again. I could say left and right. Left is the word. If left is empty, so I can check it. Left is greater than zero. Then I just want to have the word as such. Otherwise I can just put the, the right. Now let me put it, take the value from the result. So it's pretty, pretty much close with the, you know, functional solution of that, even though I would love to have combined more than two at a time. So that's how, you know, you could leverage the infinite streams. It does. Okay. So another important, you know, problem, what we see in, see while using the streams is, you know, Java, it does have an optional type. So suppose you have a stream of optional value. Say one, essentially I want to get it out for all the, you know, wherever there is no value, get the value present and do some operation of the, that is a common thing to do. So you will have to do something like this. I want to filter wherever there is a value present. If I don't have a value, I want to get it off the thing. I could use the optional is present. And then finally I can map and say optional get another value present. I want to get that. And then I want to print that. You get the one and two. Every one doesn't have any value. That's been, which is a pretty common operation, but you have to go through quite a bit of settlement here. If you move to the way to do that in a waiver would be something like this. I can create a stream of, it provides a new type called option, this one, option of let me take one and option of two and finally, and I can do a flat map. So I can just written it as it is and say right. And you get the, instead of this, you could use the identity also, which is a function one. Well, that's an interesting reason why they created a new type called option instead of using the option one. Because if you're mapping and value to an empty one, it does change the type. Whereas here it will rotate. So with that, we'll go ahead and see what happens. When we throw an exception of streams. So your composition time will break and you don't have to go back to your old style of trycatch and do something like that. So let's take this example. So I have a stream of string here, which I want to convert to say URI. So I can say map and let me take this value and I can say URI. So that's, you're going to get an error, which is the typical check exception. Whenever your function throws a check exception, either you have to handle that or you have to declare it. But this is the, you know, lambda, I don't have an option to say throws or anything like that. For that, that's a simple solution. Usually, you know, the recommended approach is to use the runtime exception in this case. But that's a simple way where you can convert that exception to, I mean, kind of make the compiler happy by saying, you can say unchecked. So now compiler is happy, it's not going to complain or anything. If I have, if I introduce, you know, something is wrong, obviously you're going to get that exception. It's lazy. Now you can see an exception for that percentage symbol malformed repair. So now we would like to, you know, go to the next level and handle that exception. So one of the ways to do that is to, you know, return an option. So I have created a function called createURI, which instead of returning a URI, which returns an option of URI, so I could use that here. You see that returning the sum or none. And I can use the, you know, black map and if I want to ignore those, I can do it pretty easy. That's why I can mark up. Yes. Now for each, we'll just go through one by one and it will, you have to pass a consumer function to that. Only flat map will do that. Black map will, on identity, it will convert to an empty stream. So empty stream will get ignored. That's why those, you know, none. Okay, so that's one way of handling this problem. There's another way to do that. Let's just do it. See, let's go to this example where I have a bunch of numbers and I'm just trying to read from those files for 10.exe, 20.exe, 30.exe, so on. Which works fine as of now. So let me add one more function, one more value to that and I don't have a file called pxt. That's why it throws an error. So instead of doing this, then there's a way to wrap it in, you know, try monad for that. So what I could do is I have a value and I'll wrap it in our try. Try of takes, you know, function zero, which, so what I need to do is doesn't take any arguments. Here I'll have to do, you know, read content of some value. And now let's see what happens. Yeah, so now again it wraps it in, so try has, you know, success and failure. So for 10, 20, 30, I got success and for the 40 I got failure. You can handle the way, failure the way you want. You could do get or else where you can, you know, directly pass on data. That's one option if you have an important value. Or otherwise you have a different recover option where, you know, based on the exception thrown, you can delegate the responsibility to different set of functions. So you have a different layer. Which you could change here. So for one of the exceptions, you could use one recover and dot recover and you could put one more exception. So this way you could, so it's like if you want to read, you want to pass some data, you tried it first time it failed and they did some cleaning and then try to pass it something like that. This is a good way of doing that. Instead, if you just want to ignore that or put a default value, you can get or else. Okay, so those are the quite a few ways of handling error conditions in stream processing. Now let's move on to a bit of more functional programming concepts activated by Weber. First thing is lifting. So I have a function factorial here which is applicable for positive integers. If I pass negative value, it's going to throw an exception. So let me say factorial of 3. So factorial dot apply. Yeah, 3. So that's how I would call my lambda. I don't have the option to treat lambdas like I would call other numbers. Well, so let's printing the 6 and if I pass a negative number, it's going to throw an exception. I'm checking if the number is 0. So it's essentially a partial function that can be called positive. So now I can, you know, convert this into a say, factorial dot partial. So which is a function 1 in my case. So I'll say function 1 dot lift and factorial function we got after lifting all that. And now you got none. So if at all I'm passing a valid value, you're going to get a number or none. So that way you could lift the function from a partial function to a full function. Next thing we could see is a partial application of functions. So if I want to call add, so I say add dot apply. So you could see I have three ways to call that. I can call with one argument, two argument, or three argument. Three argument is a full call which will return me an integer. But if I call with the two arguments, I'm going to get a function back which accepts one number and returns one. If I just pass one argument, I'm going to get a function. The rest of the two arguments I'm going to return the sum. So I can see in this case I'm going to get one more function which I can apply and pass the third number. I can get the value. That's something you could do it instantly while currying is something you just apply one value at a time and derive other functions. So I could say add dot curry. You could just check the signature. It's going to return a function that accepts an integer and returns a function that adds another function. So let me say curry. How could I call this? I will pass the first number. What will I get? Another function to which I'll have to pass the second one. I'll get one more function. I can call that. Yeah, that's about currying. Let's take a look at how memorization works. I have a function which is supposed to be a costly function. It takes a lot of time. I'm just incrementing it. Let me call that function. It says computing for 10 and I'm getting the value of 11. So if I were to call it twice you would see that again it's going to compute that. Even though it's a pure function every time it has to go and perform that costly operation which I cannot totally avoid by using memorization. What I could do is I could say costly function dot memoized which will give me the moist function. Now I could just secure and you know the computing for 10 comes only for the first time. Next time it's going to be the memoized one. Now let's take a look at the lazy. So one of the simplest way of making something lazy is to wrap it in a supplier. So in this case if I call the supplier dot get I would get that number. And if I click twice it's going to get that twice. We will provide some kind of lazy wrapper around that. Let's see how that works. So I can say lazy of and I have to pass the supplier and you would notice one interesting. So the supplier gets called only once and it doesn't call it repeatedly because you could do it well. So these are the few set of features with respect to functions and with respect to stream processing. So it implements all together a set of API which could be used for making your the questions. Well the idea of the decision was to go with the immutable persistent collection. So that's where it would be much easier and effective to do this kind of thing. For Java if Java was written from the scratch today I'm sure most of these would have been the route. But since Java by principle wants to be backward compatible a lot of things are not possible in the sense you may have features available to the developer more or less but it will come with its own behavior. Something like a waiver which is a new library altogether you can always have a different. It is in fact a waiver is supported by spring data so if you are using spring data and you want to create entities you could use all these persistent collections or entity could use option you could use list or set map which will automatically call these two Java lists and whatever you thought and it will persist there so you don't have to do any additional things. A lot of say if you have a map you try to get a value from the map in Java you could get a value or null whereas the waiver map will return you an option so given a key there is a possibility that the value is not present so a lot of the APIs are much better and you don't have to take care of it. Option itself is safe. It has enough but it does have a get function so you can always try to get on option which can lead to null pointer exception but you are not supposed to call get directly you have to use get or else or one of those I mean if you are very sure that data is something like if I had a few data then you can go ahead and do get but otherwise you are not going to be. I think yeah so there is a half all how you don't have to do that if you have a list and you filter you already have a list unless you want to convert it to a Java list in that case you could use two Java lists two Java tables so that was necessary because you are forced to convert your list into a stream so how from the stream you want to convert back to list is maintained by a couple of people as such and it is a patchy we do license so I mean there is no company as such which is backing me but I believe it's already used by a lot of people I mean though I cannot predict the future it's as equal as you need it so they had a benchmark I think on the github which might be a bit dated I believe but interesting practice if you compare the waver stream to java stream java stream will be much more because just an iterator so the only thing that is common between javas 8 or 9 streams and waver stream is the name nothing beyond that java 8 is totally a mutable version of that and it's not so that's one of the reasons why it could be much faster but if you compare something very similar well for those kind of situations I think you will have to take case by case the raw performance of any particular system is quite difficult to rely upon is it adequate for your job does it provide any improvement for your role you have to look at from that perspective it's always a trade-off between do you really need it it is if you are using java already it becomes a real good reason for doing that but if you are already on python I don't say you come to java just because you know there is a waver library but if you are on java platform that's a good choice this is a library just for functional fluency there is no actor at all in this actor you will have to go for something else this is not meant for that well scala and java are interoperable to some extent you could use the same part for this also but if you are already on scala you have you know scala already has quite a few of these make use of that but if you are already on java and you are thinking of using scala for a subset of that then you could consider using this but if you are already there maybe I think if you are using spark still scala is a good incentive in my opinion because the api is much more fluent compared to java api but somehow if you are already on java api then that would be a good question to ask should I use this or this but it's not so interoperable this is a simple library right on java which you could grab and use scala will have its own glitches passing you can always convert back to java views you could use that that's exactly it it will you will have to ask is there any reason why you don't want that it's something under the hood should you really go and bother about that well that's why it's always relative you cannot always say you can't always rely upon the absolute performance they do have a Jackson extension they have a couple of extensions there is also property based testing extension you could convert it it has the converters well then I think java just a lot of time thanks for being here I hope you enjoyed it thank you