Java Streams: Beyond The Basics

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
all right time to go again this time we are going to learn a bit more about lambdas and streams they've been there for a while but this is taking it beyond the basics we go in further this time please give a warm welcome to Simon Rito thank you very much so let's start with a show of hands and I can just about see people so who here has used JDK 8 okay very good who here has tried streams and Landers okay very good so I have the right audience what I'm going to do with this is really to help you hopefully to understand a bit more about lambdas and strings which is why I called it beyond the basics I'm going to spend a few minutes at the beginning just recapping the basics of lambdas and streams so that we know where we're at but then the idea is to help you by learning from my mistakes and there's there's a very nice phrase that I I tend to use who's not going to work okay let's try that okay appears that my slides do not want to go forward okay now that's interesting so now this seems to have frozen up completely let's try that again okay let's see if oh good that networks right so there's this is wonderful phrase a clever man learns from his mistakes a wise man learns from other peoples so that's what we're going to do you're going to learn from my mistakes because I have spent a lot of time programming as I'm sure most of you have but my background is very much from programming in C and being a procedural imperative programmer and then moving to Java and being an object-oriented imperative programmer and so when it comes to using lambdas and using streams if effectively you need to understand about functional programming and I have no background in functional programming before JDK 8 so I have learned a lot about lambdas and streams and how to use them effectively as I have gone on with the code so let's just take a couple of minutes as I say to recap on lambdas and streams so we know exactly what we're dealing with the first thing is Lander expressions the key thing about lambda expressions is it's about enabling you to have parameterised behavior in a much simpler way than it was before because in jdk 7 and earlier if we wanted to create a new thread and we wanted to do some kind of work if we didn't want to create a class which implemented the runnable interface we could use an anonymous in a class which is kind of clunky and involves lots of boilerplate code and all sorts of things that just make it unwieldy so we end up with something like this where we have to say it's a new runnable we've got braces we have to specify exactly that it's a run method and it's a public and it's a void and all this sort of stuff in order to do some stuff so with the lambda expression since everybody here has used lambda expressions you know what I'm talking about it's much simpler we reduce that into in effect an anonymous function so we're now saying that the parameters we're passing to this anonymous function are no parameters empty brace brackets and what we want to do in the body of that anonymous function is do some stuff so it's a nice succinct way of having our code execute and actually express what we want to do now one of the other things about lambda expressions is that in jdk 8 large part of the compiler was rewritten so that the compiler could make better use of type inference and it could figure out what types were without you having to state them explicitly if we look at this as an example what we got here is a sort method and it's a generic sort method has a generic type parameter T and what we're going to do is we're going to pass a list of type T to that and we're going to pass a comparator which uses wildcards to say it's a a parameter which is something which is superclass of T okay now if we want to use that what we can do is we can say okay let's take a list in this case it's a list of type string and get that from somewhere and then we want to sort it so we'll call our sort method and we'll pass the list in and then we need to create a comparator comparator is a functional interface so we can use a lambda expression to represent it in this case we're going to pass two parameters string X string Y and we're going to return the difference in length of those strings so we're going to sort our strings by length so that's all very good but the compiler is now smarter the compiler can look at that and say ah well I know that list is of type string strings a final class so in terms of the comparator it must be a comparator of type string so we don't need to explicitly state that x and y are of type string we can leave that out and the compiler will fill in for us the fact that both x and y are strings what this gives is something which sometimes people get a little bit concerned about because they think oh hang on are we sneaking dynamic typing into Java the answer is no this is still fully statically typed there's no avoidance of fact that these things are strings it's just that the compiler is filling it in for you and the way we like to say that this works is that we're actually getting more typing with less typing and that's terrible pun which relies on the English language having multiple meanings for the same word functional interfaces this is the places where you can use lambda expressions so a functional interface is by its very definition and interface and the key point about a functional interface is it can only have one abstract method in JDK 7 and earlier this was pretty simple to recognize a functional interface should you actually be able to use one if you look at things like actionlistener there's only one method therefore it's an abstract method and it must be an abstract functional interface in JDK 8 it gets a little harder to recognize what is a functional interface reason for this is because in JDK 8 in addition to introducing lambda expressions there's also the inclusion of default methods in interfaces what this does is provides you with a way of having multiple inheritance of behavior as well as multiple inheritance of types it's not complete multiple inheritance in Java because there's no multiple inheritance of state but you do now have multiple inheritance of behavior in addition to that we also allow you to use static methods in interfaces so that's a change between JDK 7 and JDK 8 so you can have as many default methods as many static methods you like in an interface but in order for it to be functional there must be only one abstract method and if you want to you can use the annotation functional interface and have the compiler check for you but your interface actually does have just one abstract method now when it comes to streams the key point about this is that what we're really dealing with this is where we start getting into the functional approach is a pipeline of operations and the structure of that pipeline is at one end we have a source source of the elements that we're going to process through this pipeline we pass that source of elements to zero or more intermediate operations an intermediate operation is one that takes as input a stream does something and generates as output that way you can feed the output of one intermediate operation to the input of another you can chain them together as many times as you like and do whatever processing is required by your code once you've done all the processing in the intermediate stages you need to generate some kind of result you need to have the other end of your pipeline and that uses a terminal operation terminal operation takes as input a stream but doesn't generate as output another stream it might generate a list it might generate a single result or it may generate no results at all but it could have a side effect and a side effect in this case is something like printing a result printing a message so if we look at a simple example of that I've got a set of transactions here that I want to process so in order to do that I need to get my source so I call the stream method on that and then I do a filter where I use a lambda expression to define how I want to filter it so this is our behavior in the parameter and we say we want to get all the buyers who in the city that was London we pass the results of that which is a stream of buyers who are in London to the map to int method look why did that do that anybody know how to switch between modes come on Dex thank you displays yes my sir thank you very much whoever that was Oh cook right there we go yeah yeah so then we pass it in to map to int where we want to map from the buyers who are in London to price associated with that transaction we get a stream of integer values and then we pass that into sum which is our terminal operation that adds up all those values and then returns it as a total there are a number of ways that you can get stream sources so there's clearly the stream method on collection you can also have a parallel stream which will use the fork join framework underneath and split the work up into a number of parallel streams and have them execute in parallel if you have an array that is a form of collection but because it's not a collection object you can actually turn it into a stream using the arrays dot stream method or you can use stream dove and parser an array of values to that there's also some useful static factories things like in-stream dot range files dot walk that allows you to go from a certain point in your file system and just have a stream of directories and files from there and then in terms of terminal operations it's quite important to understand some of what happens there even though it appears that you have these streams being passed from intermediate operation to intermediate operation and so on that's not actually the way it works underneath underneath all these things emerged into a single set of operations to optimize the efficiency of how these things happen so if you're doing something like a find first what you're not going to do is pass all the elements from your source through a filter pass it all the way through a map and then look to see when you find the first one you'll pull each one through the whole pipeline as its required and then when you get the sort of find first that returns positive so you actually got the first result then you can stop processing at that time so you don't have to process everything in the stream there's also a number of optimizations that happen underneath in terms of the way that the streams are classified so that you can have things like saying a stream is distinct we know that the stream doesn't contain any duplicate elements if you pass a distinct stream through the unique or distinct method then it's not going to do anything it's going to avoid doing extra work so let's look a little bit of some of the details about how we can use these lambda expressions and streams in effective ways now one of the things is delayed execution and this is this is a classic sort of problem that we have Heisenberg's uncertainty principle applied to software now Heisenberg's uncertainty principle for the physicists amongst us is all about quantum mechanics it's the idea that the act of observing something changes what you're observing but this also applies quite often to software and we get something like this where you've got a logger and we're going to call the finest method on that and we need to pass the message to that method so we call a method called get some data now get some data could be a very heavyweight operation it could take a long time to process whatever is needed to return that particular message and the problem with this is that even if you set the log level to info it still has a performance impact because regardless of what the logging level is in order to call that method you're always going to call get some status data it's going to generate the result and then pass it to logger dot finest so anyone who gets to logger top finest that the logging API is going to go all we're at level info we don't need this message so we'll just return so you've still had the overhead of actually creating that message so the logger determines whether it's required or not and regardless of whether it's required or not you're still generating the message in JDK 8 what's happened is that the logging api's have been modified there's now new versions of all the logging methods like finest to finer and so on which now take a supplier a supplier is a functional interface and as the name would suggest it supplies a result but the important thing about this is that it actually doesn't give you the result it gives you a description of how to create the result if we take our example there logger dot finest get some status data we can change that very very subtly into a lambda expression so now we're saying rather than using get some status data to generate that message directly use a lambda expression to represent the supplier supplier doesn't take in it in the case of the method it doesn't take any arguments so we have empty brackets and the body of that lambda expression will be to get some status data when we call logger dot finest we pass the lambda expression to the logger the log of n says if we're at level info we don't need to do anything it returns it hasn't used get some status data if the logging level is at finest then it goes up we need to call the supplier uses the method calls it get some status data is called and we generate the message so avoids the the overhead and it really is about having a way to describe how to create that message not actually the message so if the logger doesn't need the value it doesn't invoke the lambda and you can use this in other places as well so if you've got things where there's a conditional on whether you use the parameter that's being passed to the method and you don't want to have the overhead of actually doing whatever is required to create that parameter in the first place pass it as a lambda expression using a supplier and then decide whether you need it or not at that time so the next thing we want to talk about is avoiding loops in streams now this is where we start getting to the difference between functional and imperative programming the thing with functional programming is that you really shouldn't modify state that's one of the key things about functional programming is do not modify state you should have a function which returns the same result regardless of how many times you call it with the same input value so there should be no state involved which might alter the result if you call it with the same input value now the other thing about Java is that in terms of lambda expressions and anonymous inner classes before that what Java does is it supports closures over values not closures over variables this is quite an important thing because it restricts how you can access variables in the surrounding scope in anonymous inner classes you had to mark any variable that you accessed within an anonymous in a class from the surrounding scope as final its value could be set once and once only you couldn't modify it within the anonymous in a class in lambda expressions the same rule still really applies in that you can't modify the state of a variable in the surrounding scope but you don't explicitly have to mark it as being final but it must be effectively final which means it behaves the same whether it's marked final or not so its value is only set once the problem with this is that state is very useful as Java programmers we use state all the time and state is good now here's an example of some code that I wrote so I said about thinking to myself okay we've got lambdas in JDK eight we've got streams what I wanted to do is find a list of all the places where you could either have a source of a stream or you had a per method that took a parameter there was a functional interface so I could use a lambda expression there what I did was I actually wrote some code and I went through all the the api's and I found all the places where there were functional interfaces being used as parameters and all the methods that return the stream is a source I built that up as a list in fact I build it up as a hash table and then I wanted to print out sort of summary results and I thought well you know I'm using lambdas and streams I'm going use lambdas and streams to find lambdas and streams great so I had my hash map and I thought right what I want to do is I want to count how many methods there are that return a string so the hash table that I had basically had the key as being the name of the class and then the values associated with that class was a list of method names in order to do that and count them up I thought right what I'll do is I'll use a stream from the the key set of the hash map and then I'll use the for each method so I'm going through each class that I have and then I'm looking at to see whether the the number of methods that I've got associated with that I want to add those things up in order to create total so I thought mmm write state this is important so I'm going to be clever here because I know that I can't modify the state in this variable from the surrounding scope so what I'll do is I'll use a long adder long adder was a new variable or new class that was introduced in JDK 8 and it was designed specifically for this sort of situation the idea of a long adder is that if you have a situation where you've got multiple threads or trying to modify a single variable obviously you need locking to avoid inconsistent data that can be expensive and if you've got a situation where you've got multiple threads that are frequently reading from something but not frequently so they're frequently writing to something but not frequently reading from it then you don't need to really lock it what you can do is you can say ok let's give each thread its own copy of the variable because they're frequently writing to it they can write to it independently and then when you need to read from it which you're going to do infrequently you bring all those results together and generate a single result so this is this is you know this should be perfect it should be ideal so that's what I did I said right let's create a long adder and then I'll have for each and I'll say okay I'll use a lambda expression and I'll say that for each element take the the elements that I've got associated with that class which is the methods take the count of that and add it to my long adder great solvers problem everything works so I showed this to one of the engineers at Oracle because I was working at Oracle at the time he said ah no that's that's not functional that's that's not the way to do it so I can I went away and I thought okay I'll have another go at that and the functional way to do that is like this so now rather than having a variable even if it's a long atom which is one that's designed for this sort of situation what we do is we say okay take the stream I'm in map to int so we want to map from the elements that we have in the hash table the classes map that to an integer which represents the number of clock methods associated with that class that gives us a stream of integer values which are the counts of all the methods for each class pass that into sum which adds up all those values in the stream and gives us a single result so now we have a nice pure functional way of doing this so then there was another thing that I wanted to do which is a bit more complicated similar kind of idea but a bit more complicated in this case what I wanted to do was I wanted to print out all the methods that could use functional interfaces and I also wanted to keep a count of how many of them were new in JDK eight so I'm trying to do two things at the same time and again I use the same approach as I did before which is to use a long adder but this time I needed a slightly more complex lambda expression the body of the lambda expression so here I've got a block of code where I'm saying okay output I'll print out each of the methods as it goes past and then check to see whether it's a new method in that class and if it is add one to the count of new meth it's and we get the counter new methods and again the engineer said no that's not a functional way to do it so I thought right another crack at it and I did this I thought okay I use map to it last time I'll use map to it this time so I said okay map to inte but this time rather than having state outside I'll have a variable inside the lambda expression so I've got new method which will be set to zero initially I print out the method and then look to see if this is a new method and if it is I set new method to one what that gives me is a stream of zeros and ones to indicate whether or not these are new methods pulse that into some and get my result now this is this is fine you see because I can make this parallel and I don't have to worry about the fact that the the new method variable is state because being within a lambda expression it's isolated but of course the problem is it's still not purely functional there's still state being modified within the lambda expression so we shouldn't do this so we need another way of doing it so now I went away and thought about it again and I looked at some of the documentation and I came up with this so now what we do is we say okay rather than doing it is one step we'll do it as two steps and we'll use this really handy little method called peek what peek does is it takes the input stream and it simply passes it directly to the output stream but it allows you to look at the objects of the stream as they go past and do something with them so in this case what I'm doing is I'm saying okay take the stream as the elements go past print out their values so that a handle is the idea of printing what we need then we'll pass it to map to int where we can use the is new method and we'll use the kind of tertiary operator so we're not involving any state at all and then we're going to return 0 or 1 great so now we've got no state involved we've got two step process this is all good isn't it no problem is that apparently if you have side effects in your functional code and printing is a side effect then that's not purely functional so even though state involved we have a side effect so we're not strictly speaking functional so I went away and I'll actually ask the engineer I said well okay so I look at this I can't think of a different way of doing it yeah I want to print the message out how do I do it is it are what you need is an IO monad I'm like okay I'm done this is good enough okay so the next thing I want to talk about is the art of reduction or the need to think differently again now what I did well when I was at Oracle we used to run lambdas and streams hands-on labs and so we put together a number of exercises that were designed to help people understand how to use these things one of them was a fairly simple exercise it was the idea that you have a file which contains lines of text what you want to do is to find the length of the longest line in the file using lambdas and strings and the hint that we give to people is that the bufferedreader class in jdk 8 has a nice new method called lines what that will do is it will turn you a stream of the lines of text in your file great so the solution to this is actually very trivial you simply say ok use your buffered reader create a stream source by calling lines pass that to map to int so you map the lines of text into the length of the lines of text parse that into max as your terminal operation to give you the maximum value and then because that returns an optional because we don't know if there are going to be any elements in the stream so we return an optional we need to get the value from that so we just do get as int and that will give us the length of the longest line in the file so it's great ok wonderful but then I was doing this and somebody came up to me and he said okay well that's very nice what if we change the problem of it what if we say find the longest line in a file not the length of the longest line find the longest line in the file and so this was quite a while ago and I thought to myself okay how do I do that started thinking about it in terms of using streams using lambdas and I came up with a solution which I call the naive stream solution and this is what it was I said okay we want to take that one find the longest line let's take our lines from the file let's pass them to sort and we sort them by length we're longest first then we'll pass that to find first which will simply give us the the first element from that stream which will be the longest line in the file and then because that returns an optional we simply call get to get the value so yeah great that works job done I'm good no not really because if you think about that it's probably the most inefficient way you could possibly do that because you're going to have to read in all the data you can have to sort it it's going to be involving lots and lots of time it's going to involve lots and lots of resources especially if you've got a very big file so that really isn't the optimal solution to this particular problem so I thought ok there must be a better approach to this using functional programming so I kind of went back to basics and I thought to myself ok if I was doing this without functional programming if I didn't use lambdas and streams how would I do it I do like this it's very simple I create a variable called longest which has an empty string in it then I have a while loop which simply breeds each line from the file until we get to the end of the file for each line in the file we look to see if the length of the string that we've just read is longer than the longest string we already have if it is we change the reference at the end of that loop we have the longest line in the file great four lines code so you think but that's that's easy why do I need functional programming well the answer is yes it's simple but the key point here is it's inherently serial you know we have this for loop we have defined the way that the code must execute because we know how a fall it works so we must execute the code like that we can't make this parallel even if we wanted to we also have a problem of it not being thread safe because we have this mutable state so longest is our variable with mutating as we go through so even if we could separate that loop up and do it in a different way and have parallel execution we'd still have the problem of mutating all state and locking and things like that so then I thought right let's do a bit more research on functional programming and understand a bit more about how that works and if you look at functional programming you find that a lot of it's based on what's called lambda calculus hence the name of lambda expressions in JDK 8 and that that's really kind of a mathematical approach but what it relies on a lot it's the idea of recursion so if you want to do a loop in your code rather than using an explicit loop use recursion to do that and this is actually a very good sort of interview question is to give somebody a simple loop and then say ok if you wanted to do that same thing without using a loop without using a variable how would you do it and obviously the answer is recursion so I wrote this bit of code just as a sort of learning experience so I said ok let's write a recursive method that will take our set of strings and give us the longest string from that so I've got this method which takes a string as parameter which is the longest string we found so far it takes a list which is all the strings we're analyzing and it takes an integer I which is the index into that list as to where we've got in terms of our search and then not getting too much detail but basically we recursively call this the blue line is where we recursively call it if we haven't got to the end of the the list so for each element in the array what we basically the list what we basically do is say okay look at the longest line that we've found so far compare it against the next one in the list and decide which is the longer of the to keep that and then recursively call it so we maintain the state by using recursion at the end we check to see which is the longest return that that kind of bubble all the way back up and we get our result if we want to use that then we can read all the lines from our file into an ArrayList and then we simply call find longest line find along a string with an empty string is our starting point the lines that we want to read and test and then start index 0 great so now we've got a different approach we've got one that doesn't have an explicit loop there's no mutable state so presumably we're all good well no because of course if you've got a large number of lines every time you read another line you're generating on a stack frame and you know you're probably going to hit now the memory exception reasonably quickly because you're just using up so much memory so it's not not the best way to do it but we have learnt from this so in order to discover a better stream solution what we need to do is use the approach that streams has now fundamentally streams is all about filter Map Reduce where you can you know reduce the amount of data you've got by filtering it you can map it in two different forms and then you can reduce it into a single result based on whatever you want to do in terms of this problem what we're dealing with here is we don't need to bother with filtering we don't need to bother with mapping we just need to reduce all the lines in the file into one line which is the longest one okay so if we look closely at the reduce method in the stream class what we'll find is that reduce the method signature takes a binary operator as a parameter and the binary operator is called the accumulator and that will return an optional of type T and if you look at binary operator what you find is it's a subclass or by function by function is a function that takes two inputs and generates signal output and in the case of by function you can have different types for the parameters and the return type binary operator all the types are the same so you have two objects of the same type and you return an object of the same type so the key that we need to kind of use to unlock this puzzle is to find the right accumulator now if you look at the description of the accumulator in the API documentation what it says is that the accumulator takes a partial result and the next element and returns a new partial result so this should seem familiar because when we did our recursion that's pretty much what we did we took our partial result and the next element and we recalled we called our method recursively so this is essentially the same thing what we're not doing here which we did in our recursive approach was it generate lots of stack frames and have the overhead of creating a new list in order to make this work so we end up with this so now we say that we take the the reader we generate a screen source lines and then we do a reduction we use the reduce method and we pass an accumulator into that so our binary operator binary operator takes two parameters X and Y and again because of type inference the compiler will know these are strings and we simply return which is the longer of those two strings the key point here is X because X remember is the partial result so X is what actually maintains the state for us so it's within the string we're not doing it by doing recursion but the stream code underneath is maintaining the state for us we don't see it explicitly in our code but X gives us the partial result that we have and then Y gives us the next element in the in the list so I went to I went to my favorite engineer Stewart Marx nice look I have done this it is wonderful I have done a reduction I've gone through this whole process anyway yeah that's really nice except there's a much easier way of doing it so what you can do is you can simply go okay use Max and rather than using max which takes a stream of intz as an input you can use max which takes a comparator as a parameter and you can say okay do read at lines passing into Max where you compare each of the elements based on the length and then that will give you the longest element in that comparing them by length so it's just an interesting sort of approach in terms of understanding how functional programming works and then looking at the documentation so let's talk a little bit in the little bit of time left about what's happening in the future with lambdas and streams because there's a few things which are being added to JDK 9 which will make life even easier for us when it comes to using streams and lambda expressions most of them are around adding new API s so one of the things that's going to be added or has already been added if you go and look at the early builds of JDK 9 is that the optional class now has a stream method associated with it and this is kind of interesting because when I've done descriptions of optional I've always kind of described optional as being a stream which has either 0 or one element in it and so now you can actually treat it that way and if you call stream on an optional what you'll get is a stream that has either 0 or one element in it depending on whether there is a value associated with that optional there's also a new method on in the collectors class this is a bunch of utility methods which is flat mapping and what that will allow you to do is to generate a collection but use a function which will allow you to map from the values that you have two different values because it's flat mapping you can potentially create multiple values for each value on the input stream so if you had for example your input stream as lines of text you could use flat mapping in terms of your collection and separate them into individual words and then collect those into a list so you could do that as a single step rather than having to go through flat map as a step within your stream and then pass that into your collect using collect a list a few other places where there are some support for streams so in terms of the matcher class there's now the ability to get the results of that matcher so pattern matching as a stream so you can stream match results same with scanner so there's now we're doing find all based on either a pattern as a string or pattern as a pattern object and you'll get a stream of match results of that and then if you want to get access to the raw tokens in terms of the scanner then you can do that as a stream of strings a few other places where you can get stream sources from there's in the network interface you can now get the the addresses associated with an interface you can get these sub interfaces you get the network interfaces just kind of useful utility methods to get the various bits of networking information as streams and then also in terms of permission collection you can now get the permissions as a stream parallel support from files dot lines this is kind of an interesting one because if you think about reading from a file typically you're going to read it sequentially but you might want to actually process in parallel to get better performance so what this lines method on files will do is actually enable you to map the the file into memory and then the stream source can be generated as a set of parallel sources by dividing up the file memory map file into kind of blocks and so what it will do is it will effectively split it for every two threads it'll split it in half based on the nearest line boundary because obviously you can't split it exactly because it might be halfway through a line so it'll split it based on the nearest line boundary and then use that set of lines as input to one of the threads that is executing in parallel and if you look at the performance improvement on that the left-hand side you've got the the kind of chart which shows how the bufferedreader dot lines method works and so that that's essentially either doing it in serial parallel parallel is actually slower which is kind of what you'd expect really but if you use the files dot line because it memory maps the file rather than trying to do it in parallel and doing reads from the file then you get much better performance so if you're not worried about the order of the lines that you're reading from the file then this can actually be something that will really improve performance a couple of other things that have been added there's stream dot take while and this is kind of sort of loosely related to the fine first kind of thing what this does is it says have a predicate which defines what you're trying to some sort of yet some predicate that you need to be true or false and then what will happen is that the string source will be read until that predicate is true so it'll read all the initial elements of that stream until the predicate is satisfied and then it will stop reading elements from that stream so you take while the predicate is true so just very simple example here let's say I've got some data coming from a reader and I want to turn that into integers and then I want to read all the elements from that stream results until I something that's less than 56 so all those will be read and then they'll be printed out as soon as I get 56 or higher then the stream will stop the one thing that you do need to think a little bit carefully about this is what happens if you've got an unordered stream is if you've got an ordered stream so there you know linear in terms of their values then that's okay but if you've got an unordered stream then you might get a situation where the stream will stop even though values subsequent values will actually still be within the predicate so it's just something to be aware of and then the reverse of that is drop while so rather than saying keep taking elements from the stream until the predicate is is satisfied what it does is it says ignore elements in that stream until the predicate is satisfied and then start taking the elements from that so if we take the same example what we're going to do is going to ignore all the elements below 56 then when we hit 156 or greater then we'll start taking elements from the stream and carry on from there so just to conclude basically lambda's provides us with a nice simple way of parameterizing behavior streams API provides a nice functional start up programming in Java which gives us a very powerful combination but we do have to think differently as traditionally imperative programmers if you haven't done functional programming before like me then you know think very carefully avoiding loops the one thing I would say there is if you think of using for each in your stream stop and think about it again do you really want to use for each is it really the right approach because quite often unless you're doing something simple like printing out values in a list for example then for each is not going to be the right approach so think very carefully if you've got any kind of mutation of state any kind of like collection anything like that for each is not going to be the right thing to do think carefully about reductions and how they work like I say partial result and the next element figure out how to do things like that more to come in JDK 9 and there's also some plans for things to go into JDK 10 and then I'm going to put a shameless plug here for the company that I work for now which is Azul and we have an open-source version or in fact it's open JDK build which is called Zulu so it's free we encourage people to use it we have early access versions of JDK 9 already so go and have a look at that Zulu dot org and with that I think I may have three minutes for questions so if there are questions so question the other front there you don't have up front up front there we go so have you experienced problems with checked exceptions within the lambda expressions when you working with streams so checked exceptions within lambda expressions yeah this is one of those things which I did talk to Brian about this which is that if you throw an exception within the the lambda expression that you're doing and you're doing and you're using something like predicate or using you know any of the standard classes they don't have exceptions associated with them so unfortunately there's no easy way of doing that you have to handle the exception within the lambda code this is just the way that it works so yeah I can't give you a better answer than that you just have to handle the exception internally don't see any other hands oh that wasn't him the background front have you done any performance comparing between lambda expression and the old traditional a while loop um no I haven't yeah I have to me I haven't done a comparison of performance between using a lambda expression Kirk would you like to comment on that is a lambda expression and a stream more effective than a for loop identical okay so I guess the advantage there is that you can we easily make a stream parallel versus a for-loop you can't so reserved there was another - somebody put their hand up over it yeah oh right same question Oh same question okay okay well I guess that's it well thank you very much you
Info
Channel: Jfokus
Views: 56,012
Rating: 4.8628259 out of 5
Keywords:
Id: TCJdc9SYwlQ
Channel Id: undefined
Length: 49min 20sec (2960 seconds)
Published: Tue Feb 23 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.