Tomasz Nurkiewicz — CompletableFuture in Java 8, asynchronous processing done right

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
it's time to start the next talk don't wash nor give each correct yeah we'll talk about new Java API completable future welcome ok so good afternoon everyone our last with ya that's as far as my Russian goes so during this presentation I'm going to show you not a language not a library just a single class so there's going to be a one-hour talk about a single class originating in Java 8 so this looks quite insane but this class is so essential and it enables us to write programs in such a different way that I think it's worth it to actually understand how it works from from top to bottom so we're actually going to look just at completable future Java util concurrent completable future which is a subclass of or actually an implementation of the future interface it has a bunch of new methods which we're going to explore throughout this hour there aren't going to be any slides during the stock just intelligent just code so make sure you all see the code if it's too small for you or anything else wrong with it just let me know I will adjust it so once again just code pay attention and let's go so let me show you something this is probably the simplest piece of code you can actually imagine looking at this one so what it does is that it calls some method of some class and you pretty much have no idea what's happening underneath so what it does actually I can show you the source code later on it just goes to the internet fetches HTML page of Stack Overflow of the main page of the Stack Overflow and it just looks up the first question of for a given tag so if I'm riff around this code it's not really relevant but I guess it should be fun assuming I have internet it should actually show me after about 500 or 600 seconds this is the most recent question stackoverflow I guess you know the site so if you now go to stack overflow this should actually be on the top if you look at Java questions but that's not the point the point is I'm running a method here and just looking at its declaration looking at its type I have absolutely no idea what's what is it doing underneath maybe it will return immediately because it's cached maybe it will take five minutes maybe it will break I have absolutely no idea because the declaration simply says that it returns a string which tells me nothing and as a matter of fact it actually goes to the internet fetches some data and if I run it again you can actually see that it takes about a second to complete so that's kind of how it works however there are many in many ways in which this code is broken and it's not broken because it doesn't work it actually works the problem with it is that imagine Stack Overflow website is down I know it's kind of tragic but it can be down from time to time imagine that we have a bug in our code and for some HTML page it just is unable to parse it because there's some parsing involved I have HTML I have to extract some data from it is the title of the question so a couple of things can go wrong with this code but probably the worst thing that can happen is actually if my code takes forever to run because I might have a network issue I might have an issue with DNS whatever so it would be really cool to actually have some way have some idea to run it in background have some timeout and so on so what we are normally doing in Java to make sure our code doesn't run forever it's just we upload it to do a separate thread so here we have it so what I'm doing right now I have a different a different way of calling this method so this one is blocking again it's the exact same method as the one on the top by the way by the way these tests are really crappy they don't test anything is just a convenient way of running snippets of code so don't judge me and this is pretty much just a callable so I'm wrapping I'm wrapping a piece of code and I'm I'm wrapping it with a callable and then I'm submitting it to a thread pool so that's as simple as it can get and what I get in return is a future now how many of you know the class you actually yeah obviously so for those of you who do not understand what happens here is that if a method returns a future pretty much means that it should be non blocking however it doesn't return a result immediately instead it gives you some sort of a handle handle of type string which means that I'm promising you that you're going to get a string in the future da but it's not yet here maybe it will appear in 100 milliseconds maybe it's already there maybe it will appear under after one hour you don't really know so that's what's going on we have this and this particular piece of code here however there are many issues with it so for example the only way to interact with the future is by calling get optionally there's a second second version that takes time out so I can say I'm I'm willing to wait up to one day okay maybe too much up to one second for the result if I don't get resolved within one second and then it will just timeout and nothing really bad happens but that's pretty much at what you can do with old futures so they don't really give you a lot of lot of cool and fancy api's let's say for example I want to wait for both of the futures well that's kind of simple I'm just I'm just having two futures and this line and this line is non-blocking remember so it returns immediately and we don't block the client thread so what we can do is that we can simply say Java get and later on we can say Scala dot get that's about it so first we block for the first future and then we block for the second future of course we wastes yet another thread because there's a thread running the Java future there's a thread running the Scala future and there's a client thread that we also has to block and we don't really want to waste threads because they occupy a lot of memory and and there's a cost of context switching and so on and so forth but this is relatively simple and at this point I actually have Java results and this one is this color result what it does underneath doesn't really matter this is not about semantics here so I have two strings here with blocking that doesn't matter but I have a question to you what if I want to wait for the first one not for both of them but I want to wait for the first one so I don't really care whether the Java future or the Scala future completes first I just want to get the first one and forget about the second one so do you have some idea excuse me yeah there's something like a completion service which is really executors completion service which is relatively awkward to use but it works it just takes a bunch of futures the simplest thing to do which actually I saw a few times so actually go in a loop so you do something like Java gets R and just do it really quickly so you do like Java get with a really tiny timeout like one microsecond and you do the same with Scala and you do it in a loop which is like insane because still not only you're wasting a thread but they were actually burning CPU and of course you do break when when one of them actually finishes this one I think either throws interrupted exception or returns note from interrupted exception so that's pretty terrible and completion as a completable service actually tries to address this issue rather than having a future that the only thing with what it can do is just block on the future and do nothing you have a completable future that allows you to register callbacks it just sounds really terrible because we hate callbacks actually but what it does is it's pretty much the same principle as you have in in JavaScript where you have promises not callbacks but promises well any of you using jQuery for Ajax yes so many people don't realize it but the the Ajax methods and all the others get post and so on actually return something and there's something that they return is a promise which you can later on process so you can build a pipeline we're going to learn it in just a second but also you have the exact same class in guava for many years now however using it is what's called completed it was called listenable future and settable future however using it was really cumbersome because you didn't have lambda expressions so what I'm going to show you during this talk is how completable future can help you writing non-blocking reactive code and more importantly this code is not going to be ugly and you're not going to end up with a callback hell okay so where does the completable Future come from by the way I don't have any slides and I also don't have any objections if you ask questions or if you don't understand something so feel free to ask at any point in time I guess there should be mic here somewhere so feel free to ask questions and we can pull something in a while or we can just try out stuff so it's not like I'm showing you a static code all the time okay so this is how you create a completable future that is fixed that has a constant value so it doesn't make much sense to create a future like that but it's sometimes sometimes reasonable for example for testing purposes or if you want to have some sort of placeholder so you're creating a completable future which has a fixed value of 42 which means this future is a handle for some integer however if I call that gets I'm pretty much guaranteed that it's not going to block it will just return 42 immediately because this future is already completed so it's just a way of like changing from a type to a future of that type we will see how how come is it useful however there are more interesting way of doing so so let's say I have this method most recent question about Java this one this one that was blocking blocking previously so what I can do is that there's a simple factory method called supply async that takes a lambda expression I think it's a supplier underneath but doesn't really matter so it takes a lambda expression of some type and return returns a future of that type so you can actually guess that this method is must return a string because you have a future of type string clear enough so here's our future and we can actually well we can we can block waiting for the results later on your CD operators dots are much more powerful I hope you see that something is missing here there's no timeout and something even more important there is no executor service exactly so what happens here is that I'm saying okay what time house is a good is a good answer as well who said about executor service okay these are for you guys so we are missing an executor service here it's basically the completable future says okay I'm going to run this block of code for you in the background and don't care about the the underlying executor service actually what happens is that there's this special thread pool somewhere in a fork/join pool class called common pool so I am in a four giant pool class this was this one was introduced in previous version of Java and it has this common pool which is a static factory method returning some Fred pool we have no control over this Fred pool yet Java runs our block of code in it so that's a rather poor idea especially since this thread pool is shared among all the applications for example deployed on an application server so that's really bad and so luckily there's an overloaded version and this applies to many other many other methods that we're going to see today there's an overloaded version that looks exactly the same but takes a second parameter which is an executor service and by the way I already mentioned that completable future implements future so this one should still compile so completable future is just an implementation of future however if you want to be more if you want your api to be more robust just return a completable future and if someone doesn't understand the new api he can just treat it as a standard future okay everything clear so far we will get back to the futures but we will learn a much more powerful way of handling futures without actually waiting sorry for handling timeouts for handling timeouts without actually waiting okay everything clear so far just now your head okay cool so what's so exciting about this new class I haven't shown you that yet so a future the standard future has like five methods in total that's the whole API provides that's why I said it's not really that robust and doesn't really provide you that many features the completable future has a few other methods so let us just quickly browse through them so we have 45 minutes left so I have like one minute per method so time start okay so we know how to create a completable future you use supply acing that's like the canonical idiomatic way of creating a future so now what we can do with this one I have a future of typed document here's a here's another more low-level method that's for a question for for Java tag it returns a document that you can treat it as an XML document it comes from some parsing library called J soup it's not really important but what I got into in turn is that since this method returns come on did it stuck since this method returns a document I actually get a future of type document so what I can do with that future assuming that my computer is not stuck which is really awkward okay so I'm going to talk for a little bit about the code oh yeah it cuts unblocked it wasn't my fault just some garbage collection or something so since this method returns the document I have a future of type document and this one's pretty simple what I can do with this one of course I can just go for dot get which clearly returns a document and then I just I'm standing up right here I'm going away from the code because someone's taking pictures so I want to look better so this one returns the document and then I can just call dot get and then operate on this one as usual however don't get as you probably know is blocking so this is definitely not what we want to achieve so what happens here I can register a callback and this will become painful in just a second so don't go away yet so what I'm doing here is that then accept just as almost every other method in the new API is non-blocking which means this method is not going to wait the execution this method is not going to wait for the response for the document itself if you don't see it this is actually let me add a time yeah this is actually a document so it doesn't matter that Java is a future of document the callback receives what's inside the future which is a document so that was fairly simple I'm registering a callback here and this callback will be invoked one day sometime in the future when the actual actual future completes this sort of works and we're going to use it from time to time but there are better ways so there's this method called then apply what then apply is doing it this is actually to prevent the callback hell so what then apply is doing this one is that it takes the future let me start from this it takes a future of type document and then it looks almost exactly as then except so it takes a document as an argument and does something so it looks like a callback right but what's really important is that this method returns a future of type element where do you think this element comes from where what's the reason for this type here excuse me yes okay so the answer was that this expression has to be of type element and the compiler infers the type and knows that the resulting resulting future has to be a future of type element but what does it tell us as well I mean if this expression returns a future it means it's non-blocking as well so we don't get a an element in return it's not a blocking a blocking call that waits for the response does some transformation and then returns it because if this was the case we could just call Java dot get and then do all this what's here yeah we can just go for this one and this returns an element and our lives would be much simpler but this is not the case because this transformation actually returns a future of type element which means it's non-blocking and this of course can go on and on so I can go I hope you're familiar with Java it by now you should be so what this one does is that it takes a future of type elements which is title elements this one and applies on the contents of that future yet another transformation this time it takes an element and returns and calls text methods so I can actually go here you see there's a text methods on on a class element so going back here this time we have a future of type string I'm going really slowly here but you'll see in just a second how powerful this transformation is and what happens next is that we take a future of type string we call string length on the contents of that future and get a future of type integer do you understand what happens is here this is really crucial because this will allow you to sink into the reactive world or completable future nodding your head okay but there's one question yep this is an excellent question and we'll get back to it in just a second okay and it's actually not that straightforward which I was painfully which I painfully experienced okay so there's like quite a lot of work the question was maybe you haven't heard it which executor service actually executes all these transformations and we will get back to it so there's like a lot of code here and a lot of intermediate futures but there's nothing preventing you from actually chaining all of this together so what happens here right now is that we have Java which is a future of type document and then we say then apply first transformation then apply second transformation and then apply third transformation and what we get in return is integer is a future of type integer so if you forget about these it actually looks as if you were calling normal Java methods on all of this so you're just having an object and you're applying one function the second function third function and so on and so forth on a simple java value even though this java value is not yet here it will be in the future so what happens here is it's not really applying a function it just registers our will that a function should be applied on the result one day and by the way all these methods are returning new future which means that the actual future is left intact so we can just stop chaining here if I'm I can just extract this part for example and I can work with this future independently so I can do some sort of like forking so I have one fewer there's one future this one that originates the actual value the one that represents computation and I have two independent streams one that applies one set of transformations and the second one that applies a different set of transformations even though they all share the same underlying future so okay let's get back to this one is this still understandable for you so it's just like in lining methods altogether so this was then apply and this was really simple and but really really powerful the whole purpose of all this juggling with code and juggling with callbacks is that you avoid blow so there's no blocking involved altogether until we actually hit this method which calls dot get but that's like a minor thing okay now we're going to get into some really meaty examples so imagine you have a future I'm just going to throw it out for a little bit we have a method called Java questions that returns a future of type documents so let me just go quickly through it you see Java questions method returns a future of document and what we want to do then having this document you now understand that doc is actually of type document so it contains the contents of the future what we want to do now is that we want to call another method on top of that document however what happens is that this other method called the find most interesting question in a document so you have an HTML document and you apply some artificial intelligence logic that can possibly take some time you're applying a method that tries to find the most interesting question in that document the problem is it returns a future a future of question because the logic is somewhat somewhat complex so what do you think what's going to be the result type of this whole expression exactly what you're awesome so the reason why this one is the future of future of question and I'm going to make it clear for all of you is that the compiler or actually the JDK is not intelligent enough to figure out that if you're returning something that is a future you do not want to double wrap it so that the contract of then apply is very simple whatever you return from the transformation gets packed back into the actual future so that's why if you if I was returning if I were returning like 42 I would get a future of type string however since I'm returning something that has a type of future of question this future of question is packed here so I have a double wrapping and this really becomes painful once you start working with it because now if I'm going to use a second and apply here what I'm going to get as a as an argument is not a question it's a question future because it's the contents of of the actual future so this it becomes really really painful and there are a couple of ways to actually work around it and if you've been working with JavaScript you know exactly how it works so you call a server in a call back you get a response from the server and in that response you are calling a server with a different request and then you have a second callback nested in that first callback and then you just have this pyramid of Def of callbacks that are just nested and nested nested and this is what I managed to reproduce in Java as well so you have Java questions and then you hit then except remember then except takes a callback but doesn't really return anything it just runs a piece of code when a future is done so okay I have a document so Java questions returns a future of document you all see the source code right you're not just listening to me cool so this one is a document a real document because the future was was completed at some point so what I'm doing right now is that I'm calling okay so find me the most interesting question in that document and this one returns me a future so this has a type future I can just extract it quickly for you right this is a future of question so what I can do right now is that I can call then except again this time with a question so now I have a nested callback that takes a result of that transformation and does something so now having an interesting question I can Google answer and googling an answer returns a future of type string which is the answer to that question but since it returns a future I'm actually having yet another callback here and it just keeps on and I look how many how many callbacks do I have here nested and at the very end I actually have some logic so the logic is actually hidden in this piece of code so this is definitely not something I want to work with although it's possible to do this with it's possible to do this with completable future don't do it and this is just like a counter example in a bad practice so what happens here is that if you have a transformation that returns a future there's a different method not than apply but this one is actually called then compose let's just go quickly through it the only difference between then apply and then compose is that then compose requires that whatever you returned from the transformation is a future so this is part of the API and look now it works if it was then apply like in previous question like in previous example we would actually have this remember but we don't because we use then compose so what then compose does the only difference between these two is that it requires a transformation at this one that returns a future but it also makes sure that these futures don't nest with each other so in a way they are running tasks one after another and we can do it all over the place so now we have a future of question we don't have a future of future of question we just have a future of question now I can do Google answer which again was returning a future of string however since I'm not using then apply but then compose I get a future of string so we already have three background tasks running one after another and in the very end I'm actually getting a future of integer and then I can do ten except which is a callback or I can do some other transformation it doesn't matter so is it clear in your head or no okay cool so it seems really convoluted and quite verbose and not because it's Java it's because I want to teach you how it works the actual implementation might look like this and by the way this code you see here is actually the exact same equivalent of this one just without all the intermediate variables so let's go back to it you have Java questions this one returns a future then compose then compose then composed and compose that's it and you might think that this is just a purely syntactic thing that we are just like avoiding whole box or nesting and whatever but think about it for a second you have a future and this future will return sometime in the future that and then we have a second operation that requires the result of this first background operation so we have one background operation that will eventually finish we have a second operation that means the result of the first one and it's also a background operation that will eventually finish so we have a bunch of tasks we actually have we have a graph of tasks depending on each other but we don't want to block if it was standard Java we would just call first method wait half a second called second method wait two seconds call third method and so on and so forth so on and so forth but we would block the client thread and this is something we really want to avoid so what happens here is that we build and asynchronous pipeline of tasks where the a synchronous completion of one task actually starts another one and this is done completely in a completely declarative way you're just saying okay when this one is done I want to run this task and when the second task is done I want to run the third one and you have absolutely you have absolute control over the graph but you don't have to do it Eclair actively there are no callbacks there is no there's no fishing around with threads we'll see that in just a second but this one is it's really cool and again if we get rid of these callbacks it actually looks as if we were just calling methods even though all of these methods are asynchronous all of these methods are returning futures and everything happens in some asynchronous world it still looks as valid Java so it's not really really that much bloated okay still clear so far yep that's also a very good question that deserves this this coin and we're going to talk about it later but the exceptions propagates but they don't propagate in the client thread because the client thread is already gone because it's a synchronous but we'll get back to it okay okay so remember in the very beginning I was actually showing you an example of and I will remove this one for a second I was actually showing an example of two futures running side by side in parallel or concurrently for that matter and we wanted to do something when both of them are completed so now I'm showing you how to do this in a non-blocking fashion let me just quickly remove this one so I have first future and I'm saying then combined do not confuse it with then compose then accept and then apply so I have then combined a second future and it takes a lambda expression you already know this is all non-blocking but you also can guess what these two parameters mean so the first one is the result of the first future when it arrives and the second one is the result of the second future when it arrives so this one basically has to wait for both of them but there's no blocking involved it's just like a callback that we register somewhere that will eventually complete and what's really interesting about this one there's an expression here that returns an integer so what do you think is the type of this whole thing hmm a future obviously I think there was a question in the back yeah no it was just someone standing I thought it's a hand raised or hit okay so we have a future of type integer and then I can simply go on and apply all these other transformations so this is I I can do whatever I want so I can take two futures combine them with each other when both of them are done so imagine there are two tasks that are very easy to parallelize because they don't depend on each other what you do is that you just call these two methods you have two futures and then you just wait for both of them so this can significantly improve the throughput of your application and I'll reduce the latency simply because it's easy to parallelize stuff and of course in the end you can just call get and it will still work so we have a future of type integer but there's even more interesting part there's the one that calls it just clean up quick so there's apply to either operator and what this one does is that again it takes two futures Java and Scala and there's a lambda expression but this one it takes just one parameter what do you think why hmm yeah so many people answer that it's the first one that executed so it doesn't matter whether the Java future or the Scala future executed or was done first it will just like invoke my lambda I forget about the second one so there's always a question what happens with the second future the one that was late nothing happens and what's really what really bothers me and what's really sad is that JDK will not even try to interrupt this second future it just keeps going on and on so that's pretty sad but that's that's how it was designed luckily you can actually implement your custom future operators rather easily if you if you really if you really hate this behavior there's yet another thing with interrupts that's maybe there will be time to share with you yeah that's a valid point so the comment was that the second future can be used in a different pipeline or in a different computation so you cannot interrupt it because some other operation might be waiting for that future and this one is not interested in in our timeouts so yeah very good point okay so we have applied to either that returns the first one to complete and there are many many use cases for that let's say you have two independent servers and you know that they both return the same result so you're just where you're just calling both of them and waiting for the first one to return a result and you don't really care about the second one so this one can make your life a little bit easier okay so we can actually scale these operators into into more than two futures so this time I have four of them and I think yeah so this time I have four futures and I have an operator as static this time and that's and that's that's called all off which takes a bunch of futures and it returns wanted to delete this one but maybe some of you didn't notice what do you think will be the type of the future that takes four futures and waits for all of them to complete feature of what yes so you would expect a future you know this is not the case but you would expect something like a list of strings right yet strings the reason being is that since you have four strings you would expect a result to be a list of these four strings where first element in the list represents the result of the first future so that sounds reasonable right but it's not the case because it's I know Java it can be at Apple as well there are no tuples but it can be a couple of four elements but what you get in return is void and probably one of the reasons is that these futures don't have to have the same type so you can technically wait for two futures of type string one future of type dates and so on and so forth I don't know but yeah you get a future of type void which means that if I do all completed then apply what I get here is actually this guy which is completely useless so I know that the transformation was done but I don't get the actual values this is pretty insane you can somewhat work around it if you go for dead run then run is similar to then except it's just a callback that it's invoked when the future is completed but the difference is that if you call get here you are guaranteed that this one is not going to block why because this callback the whole thing is executed when all of the futures are done so you can safely call get but this is just like a really foolish workarounds to to some API deficiency but that's not everything I'm actually going to remove it immediately so there's any off remember previously there was all off here at the very at the very top but there's a second operator called any off and what any off is doing I guess you you can guess is that it takes a bunch of futures and it returns the result of the very first of them and all the others are just discarded so what do you think the type of this one should be if we have a bunch of futures of type string excuse me yes yes and no so I would expect a future of type string this would be reasonable because I have four futures of type I have four futures of type string and I'm waiting for the first one of them so hey I want a future of type string because I know all my futures are of type string this time it's object because reasons and if you actually go to if you actually go to a callback of then except remember this one takes the result of the future as an argument so it's an object so it only compiles because I'm using two string here but I cannot go for for example a result length which is a valid method on a string because my result is not a mastering it's an object technically I know it's a string but yeah I still have to downcast it which is pretty terrible so it's not all that black and white with the new API it's actually pretty terrible in some circumstances yet it's still much better than what me what we had and we can just build some some layer on top of it okay let's just keep put that on for later and let me show you error handling so there was already a question about errors what happens when when an exception occurs remember future even in Java 5 this is when it was introduced first futures can actually have two results it can be a result of type T because you have future of T or it can be an exception and this is fairly straightforward if the block of code that was running in background through whining sorry through one exception this exception is later on a result of your future obviously it can't happen in the client thread so here I have here I have here I'm invoking a method that asks for questions about PHP and coincidentally this one returns or this one throws an exception so if I go for then apply in this place what do you think R is going to be this is a tricky question yes so this one goes for you and I think you were first so there will be no R because R is actually a string like this one and there is no result there is no string because the execution never finished there was no result of type string there was an exception so this one will actually never get cold in this particular case not that its non-blocking and it will run in the future no it's entirely it's going to be entirely skipped because there's simply no value that you can invoke the lambda on however if you call the old fashioned in get method it will actually throw not that the actual exception about the execution exception that wraps the underlying block of code exception so this one throws however this one is absolutely oblivious to to whether to the task that threw an exception so that's pretty bad because we want to go fully reactive and we just entirely swallowed the exception we entirely forgot about it so there are a pair there are operators for that the one of them and again the API is slightly ugly there's a method and completable future that is called handle and this one takes two parameters either either result or a throwable so if the future returns if the future completed with an exception so it's through an exception this parameter will be not null and in this case there is a and there is no code handling this exception if however throwable is null it means that this value is supposed to be not null because this is the result of the actual task so this is pretty terrible because we have an API that has two parameters but always just one is not null and the second one can be ignored but that's how they implemented it what's interesting about this one is that yet again I'm deleting the original type I'm actually returning something here so it's not that the only thing I can do here is logging an exception I can actually return a value in case of an exception of course you would normally do log error blah blah blah however you can also return some sort of a fallback value and this fallback will be propagated to the downstream operators as if the exception never happened so this is a way not only for handling an exception but also for recovering from exception and if the exception didn't appear we can run a normal transformation so if this wasn't handled but this was then apply we would get just results and we wouldn't get this part so this is basically the same thing however since we also want to handle exceptions if they occurred upstream so in one of the upper levels of the operators we go for handle there was a question or they excuse me yes for both both for success and both for failures so if the execution was successful this this value will be the actual result so it it covers both paths the successful path and the error path this one actually u-turns a future so I forgot to ask you the question but what's the result of this whole expression what do you think no no sorry I didn't catch that okay but what's the what's the result of this guy yeah yeah I see you totally get what's going on here so it was actually called recovered in the first one and it's called recovered because we recovered from the exception we don't just sit there and cry we actually took the exception and return it and translate it into some meaningful value I think but I'm not sure about it I think if you just throw an exception from any operator it will be treated as if the future through that exception so if any of the transformations throw an exception or for example take this exception and and we throw it if you just do throwing your runtime exception of throwable and this will have the effect your you're looking for but I'm not sure about it so we just have to look it up okay I don't think so because this one takes a it's a bi function no it's not possible this interface doesn't allow it but who uses checked exceptions okay and the last one which is actually very similar to handle exceptionally does the same thing as handle but it doesn't take the successful result as an argument so this callback is executed in case of an exception happening upstream so in one of the upper operators and again it translates the exception into something meaningful like say so some error code error code or whatever of course you can do logging in this part because once you return from this callback the exception is lost so it's a it's a good idea to do some logging here and that's about it so if there was no exception then this line is simply not executed and we go further okay everything clear with futures or with our handling yep okay so so the question is what happens if I have a longer chain of futures like this one then apply something something something and the exception occurs somewhere in some of these lines right so remember everything apply actually takes a an argument right it can be an argument of different type every but at every stage then apply or then compose for that matter assumes I can actually go forth and compose here assumes that you get a successful result so if an exception occurred at any point in this pipeline all the subsequent operators are pretty much gone because there is no like value to invoke them so the exception will propagate to the first handle or to the first exceptional because it can do anything with it and this is kind of similar to throwing an actual exception as long as you don't have a try catch the exception will just keep bubbling up at the stock until you get the actual exception okay okay okay so let me just quickly go back to for example all and any so the question was what happens if one of these underlying futures return or throw an exception I should say so this exception is propagated as well so if the if it's sorry I have to be more precise here if it's all off so if we're waiting for all futures and one of them even the last one throws an exception then this exception is propagated downstream because we don't have a single value so we have it has to be propagated even though all the others succeeded yeah the first exception wins pretty much I think it's lost maybe it's long on system error or something so yeah but you can ambit a built-in handling right here so if you want to make sure that every single feature is it's logged you can just go for this one and just include exceptionally on each one of them you can do it declaratively somehow and then you're going to get logging for all the underlying futures and you can actually handle all of them however that's not the end of the story because any of is interesting if you're waiting for four different futures and the third one failed or the second one then nothing really happens because the first one succeeded and it's the first one the result of the first one that gets propagated downstream so we don't really care what happened to the third one second third fourth and so on the first one succeeded so we forget about everything however if the first one the first one fails the first one as in and the one that was the soonest to complete so if the first one I mean let's say Scala was the the fastest one if Scala was the fastest one to complete however it completed with an exception then even though all the other futures completed successfully the result of any of invocation will be an exception because the first future always wins and it doesn't matter whether it wins with a normal value or one exception this is the one that is propagated we can learn later how to alter this behavior by doing it more or less manual I guess this answer is a question so I didn't catch that okay I don't think I understand but we can have a chat about it later okay no no there's no either and it doesn't work this way with with futures but you can build one yourself and if we have time we can do it okay just on screen so the question was can you like get something like either in Haskell or in Scala like having either this one or that one in a declarative manner it's not possible but it's fairly easy to to implement okay promises this one is interesting what's really cool about completable future is that you can actually create one from scratch so have a look at this guy what we saw previously is that we were either creating a completable future with some value so we were doing completed future of 42 remember and this one returns a future of integer that's already completed and that's about it we also saw that we can create a complete able future using a factoring methods called supply async which takes a block of code this one you should remember as well however there's a third and really interesting way of treating a future which is pretty much just calling its constructor and this one is interesting because it read as a future with no underlying computation it's just a holder for some value which we promise to delivering in the future but there is no background thread there is no thread pool there is no nothing it's just a container for a value and we can actually set that value later from any other thread but we'll get back to it later so this one is called never it's a factoring method for futures that never complete and this is like the simplest use case so we can create a future that no matter how long you wait for it it will never give you any value simply because there is no logic for that but there are in more interesting ways of doing so so let's say I want to create a future of type T that never completes normally however if you wait long enough it will throw a time of exception so how it can be implemented let's just forget about these lines for a second I'm creating a future and I'm returning it I'm calling it a promise but it doesn't really matter so this is very simple similar to the method above called never but what happens next is that I actually have a thread pool this is a scheduled thread pool here and I'm scheduling that after a given period of time a configurable period of time let's say one second so I'm saying that after one second I want to complete this completable future explicitly complete the future from some other thread and I want to complete it exceptionally with an exception so what happens here is that if I actually call this time out after method what do I get duration of seconds to let's say what I get is a future that if I wait for that future long enough actually two seconds then it will return or actually it will result in a timeout exception if I wait less than two seconds then nothing happens there is no value completed so what do you think how is this construct useful where you can use it excuse me hmm any of yeah that's that's a useful thing yeah exactly so what we can do is that I can technically have two futures and there can be a an arbitrary type here so this one is called timeout and this one is going to be called real logic whatever that means so this one let's say calls a database and this one is just just a fire hose which returns which throws an exception after two seconds and then I can say future damn future apply to either or any of it's the same thing timeout and here I get two results so are actually one result which is a string right and this one is really interesting so please be careful what happens here is that I have two futures one is there is the real logic for example calling a database web service whatever and the second one is just purely a timeout which will definitely fail after two seconds so I guess your you can imagine already what happens here if our real logic this one finishes within two seconds we will actually get a normal result so if this one returns 42 or if this one returns hello we will we will get hello here however if there was a timeout so if the real logic took more than two seconds to complete what's going to happen is that this callback will not going to be executed at all why because the first future to complete through one exception so this exception will actually be part of that future it will be the result of that future so what we can do later is why we can go for handle or we can go for exceptionally but there will be no result there is just and just an exception so why go through all of these steps rather than just going for future get to I mean that's pretty much the same thing right we are hmm yes exactly so this one is actually blocking so it returns a string and it blocks up to two seconds so either the real logic completes within two seconds or we get a timeout exception however if you go through all these steps and you actually combine these two futures together you get a non-blocking behavior so there are two futures they both they are both trying to complete as soon as possible and if it was a timeout then you get a timeout if there was a real logic completing then it's a real logic so that's a then useful thing to have is it clear yeah sorry yes you have to keep an eye on that because the question was is it a good practice on a busy production server because there are lots of these callbacks that are probably never going to be executed and the answer is no it's probably not a good practice but it depends on how many scheduled items you actually have but indeed there is going to be a queue of pending pending pending callbacks and these callbacks are basically not doing anything because all of them will actually trigger this code so every single callback we register will actually will actually execute complete exceptionally however we don't really care because the time the first future already completed so it doesn't really do anything but still there's like this huge queue of very short-lived but still still tasks to come okay what show you next I'm going to show you a simple refactoring how you can go from blocking API or callback based API into completable future unless there's something more interesting but I don't think so okay so here we have a method called load tag or it's pretty much just asking for questions from Stack Overflow you can see it here and I'm using a asynchronous HTTP client and the reason why it's a synchronous is that rather than returning a result it asks you to provide a sing completion Handler something this is just some API it's an example we are not really studying this API itself but what we want to do is see how we can replace callback based API s with future based API s so the first thing that you can see here is that it takes two parameters on success and on error so these are basically callbacks this is the usage of this method you called load tag and this one doesn't really return anything it returns void and it takes three parameters the business parameter let's call it like that and two callbacks what happens on the response and what happens on throwable but instead because we really love how the completable futures can compose with each other and so you don't have to pass callbacks around you could just like pass a value a future we want to refactor this method so that it uses future so the first thing is that we return a completable future of type string right because the callback that we are supposed to provide it takes a string see here it actually takes a response of type string and does something with it so that's that's what we are aiming for however we don't want to use call box we want to use futures so what I'm going to do is that I will simply return that future which is here I'm going to call it promise and put it in the very front so we haven't broke anything yet what happens next is that rather than calling these two callbacks are you still following what I'm doing by the way okay cool so first let's start from rollable we have promised what happens here great if I can write complete exceptionally with an exception and we don't really need this callback anymore because this information is going to be conveyed in in the actual computer here we have one completed so you didn't learn that method yet it's called complete not complete exceptionally but just complete and this is a way of fulfilling or resolving a future from arbitrary thread at any point in time so we just created a future disk is going to be whatever it was response get response body so this one is really interesting we have a complete able future which we create it from scratch remember we just said new completable future here so we created a future from scratch there is no underlying thread pool no underlying background task it's just a container which has no value that which has no task that's going to fulfill it but what we are doing is that from arbitrary place in our application we are just saying ok if someone listens to that future please complete it with this value and that's about it so we no longer need this callback this own success callback so I'm getting away with it and that's about it so now we don't need these two parameters so I'm going to just remove them from here I'm using factoring I don't need this parameter I don't need this parameter or I don't say you delete delete' anyway so here what happens here's what happens we have a load tag method which for some reason shines brightly but doesn't really matter I hope it's it works we have load tag method that looks much much clearer right now it just has a single business argument attack but what we can do right now remember it now returns a future of type string so I can work with that future I can for example say then accept and this is my response or I can go for exceptionally and this is my throwable remember or I can actually do some compositions so I can do then compose then combine and all this stuff and it's much easier because I don't have to decide right now what to do with the results I can actually just return it here and remember instead of blocking I can actually return this value here and let some other person decide what to do with it so this allows me to control what to do when the task is done not in the place where the task was executed but in the place where someone is actually interested in it so I think we're running out of time so if you have some questions you can catch me later and yeah I hope you enjoyed it we didn't have any slides and I hope you were able to follow so thank you very much it was a pleasure spasiba
Info
Channel: JPoint, Joker и JUG ru
Views: 55,932
Rating: undefined out of 5
Keywords: java, jug, jug.ru, jokerconf
Id: -MBPQ7NIL_Y
Channel Id: undefined
Length: 61min 9sec (3669 seconds)
Published: Tue Apr 26 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.