 Okay. Hello, everybody. My name is Miro Tsupak. I'm a software developer at the NSTech, which is a small startup where we're building a cloud platform for genomics. The NSTech is based in Toronto, which is where I live, where I attend the local Jack. But I spent the last month or so traveling in Southeast Asia. Singapore is actually my last stop. So I thought it would be fun to reach out to Michael and see if the local Java community is up for some interesting events. Yeah. He was kind enough to organize this. It was actually very last minute as well. We were exchanging messages on New Year's Eve as he was traveling. So thanks a lot for that, Michael. Thank you everybody for finding the time, so early in the new year. So the topic for today is Java 9 Episode 2, which as the name suggests, is a follow-up talk to the meet-up that you had a couple of weeks ago, which is about Java 9 as well. I wasn't here, but out of curiosity, how many people in the room were there? Okay. Almost nobody. So that's great because I actually watched the talk on my way here and changed mine so it doesn't overlap too much with those. But good to know. So the plan for today is this. We're not going to talk about modularity and G1JC, which were the main focus of the last meet-up. So I would just refer you to the recording. Those were actually pretty good talks. So if you're interested in that sort of thing, go check it out. We're also not going to talk about language features. There is a tribe of resources and effective with final variables, handling of underscores, private methods and interfaces, and a couple of really nice things. Those were covered at the last meet-up as well. We're also going to skip a couple of bigger APIs, such as flow, reactive streams, and optional, which I feel were covered well enough. So what are we going to talk about? We're definitely going to talk about JShell. We're actually going to use JShell to demonstrate the use of all these other APIs. And we're going to talk about enhancements to the collection API, streams API, completable future, and a couple of new APIs in Java 9 as well. Stack Volcker, process API, HTTP to client, and JShell. So hopefully that works for everybody. It's kind of a selection of my personally favorite APIs that are really small and often don't get that much emphasis. So I feel they're underrated anyway. And I think they're actually really useful and definitely worth talking about. So hopefully that will be interesting. And that is as far as I'm going to go with slides. The rest of this talk is going to take place in my terminals. I'm going to have a seat here. I hope you don't mind so that I can type better. And let's start with JShell here. So JShell is the tool that you can see here. Actually, can you see it well? Is it large enough? Okay, good. So it's a tool that's bundled with JDK 9 and it's essentially Java's implementation of Ripple, a medieval print loop. So it's a tool that loops continuously, reads your input, evaluates it, prints out the output. So it's very similar to JShell's as you know them from other technology stacks or programming languages, Gruy, Scala, Python. They have all had that for a while. And finally, Java is getting an official Ripple too. Ripple is really useful for a couple of use cases. Definitely if you're new to the language, if you're a learner of Java, but it can be also a valuable tool if you're an experienced developer. Really useful for just trying things out very quickly, exploring new APIs, prototyping, sort of increasingly building more and more complex code, or just kind of refreshing memory. Like if you're working on a project in Python for a couple of months and then coming back to Java and you do reminder of how certain specific things to work, JShell is an ideal tool for that. I've also used it at interviews. It's pretty easy. I think that's enough theory. Now, the main thing that you need to know about JShell is that it accepts two types of inputs. There's snippets, so the actual Java code that you want to evaluate, and there's commands to the actual JShell tool which always start with a slash and we'll use a couple of these throughout this talk. But let's start with something really simple. I'm just gonna type one plus one. And you can see two interesting things here. One plus one is two, and two was assigned to something called dollar one here. And dollar one is an implicit variable that JShell created for me. And it does that whenever you have an expression that you don't assign to anything, it automatically creates a variable for you. Could have, of course, created my own variable. I'm just gonna name it X and I have a variable called X. JShell provides a couple of keyboard shortcuts that you will see me use extensively throughout this talk. You've just seen the first one. Shift, tap and V means introducing your variable and infer the type of the variable from the expression. So that's very nice. There's also sort of standard tap completion as you would expect from any shell. So if I wanted to bring this variable, for example, I can just do something like this, take advantage of the tap completion here, and bring my variable X. There's also a few sort of syntactic shortcuts. So you've probably noticed that to evaluate one plus one, I didn't need to wrap it in anything. I just typed it as it was and got processed correctly. I also didn't need to use a semicolon at the end of my statement and it was fine as well. Similarly, I wouldn't need to worry about catching exceptions, even checked exceptions. So for example, if I wanted to put JShell to sleep, for a while, I can just do a thread sleep. That throws an interrupted exception, which is a checked exception, but I can just do something like this and it's gonna go through which is fine. And this brings us to the first commands. So there's command vars, which lists all the variables that we've declared. So there's two right now. Similarly, you can type methods and whole classes in JShell. So there's methods and types, but obviously I don't have any at this point. And there's also a slightly more general command list, which lists all the active snippets. JShell, by the way, has this prefix matching going on. So as long as you specify unique prefix of command, it's going to be found correctly. So I could have just done something like this. And that's pretty much it. If you want to know more, just type help. JShell actually has a really nice help page that tells you everything that you can do with it. Yeah, so like I said, it's pretty easy to figure out. So let's take a look at some of the new APIs in Java 9. So the first one on the list are convenient spectrum methods for collections. And Java 9 basically makes it really easy to create small immutable collections, which is something that was relatively tedious to do in previous releases of the JDK. And I'm sure everybody knows the drill. If I wanted to create a set, I would do something like this. So let's say set of strings, and let's call it a set and actually make it a set. Then to add a couple of elements, I would do something like this. And finally, to make it immutable, I would wrap it in collections, a modifiable set just like this. So that's okay. But there's a couple of issues with this approach. First of all, it's very verbose. I needed like five lines of code just to create a simple set of three elements. On top of that, it's not really a truly immutable set. It's more like an immutable view of the underlying set. If I kept the reference to the original set, which I have in fact here, I could still modify it. And there's performance overhead associated with supporting immutability, not to mention all the extra objects that I had to create in the process. So it's definitely not ideal, but Chava9 fixes that. And it fixes that by introducing static factory methods on all the main interfaces, list, set, and map. So if I wanted to create a simple list, I could take advantage of the off method here. And you can see that there's quite a few versions of this, 12 to be exact. So it's always zero to 10 elements and a single var arc method. And you might be asking, okay, why don't I just have a single method that has var arc like that captures all my use cases? And it's true, but it's for performance reasons because there's performance overhead associated with allocating the array to backup the var arc. So you're creating reasonably small collections, which presumably is the vast majority of use cases. You wanna avoid this penalty, even if it comes at the cost of polluting the API. So to create a very simple list, I can just do something like this. Let's call it a list. And if I actually try to add something to it, it's going to complain, okay, I don't know what this operation is. So yeah, it is truly immutable. If I actually try to determine the class, it's going to tell me that it's something immutable. So an interesting thing to note here, this isn't your standard array list. This is a very special implementation of a list. And those implementations are not actually a part of the public API. So you can only rely on the interfaces here. And you can only obtain them using static methods on interfaces, which are not inherited. So you cannot invoke them through the implementing class, which means that this is pretty much the only way I can obtain such a list. And that's just a really nice design pattern that I thought was worth mentioning. And it allows Java developers to modify the implementations in the future without breaking any sort of compatibility. So the API for a set is pretty similar. Again, 12 methods, zero to 10 elements, and varx. For a map, it's a bit different. And you can barely see it here, but there's only 11 methods here. So it's zero to 10 elements, or 20 in this case, because you always specify key and a value one after another. There's no varx method, and the reason for that is keys and values can have different types, and you cannot have two varx in a single method. So what they did instead is they created method of entries here, which takes a single varx of that map entry. So if I wanted to take advantage of this, I would just do something like this. And I have a small map where keys, the integer, and the value is the string. That's pretty much all there is to it. I just thought this is something worth explaining because it's something that I'm using extensively in all the other APIs, so just so that everybody's on the same page. So this brings us to streams. Collections are a very important part of the streams API. And streams learned a few new tricks as well. There's four features that I would like to mention to be exact. So the first one consists of two methods. It's take while and drop while. But let's take a step back and take a look at what we had available in Java 8. So in Java 8, I could create streams of arbitrary elements. I'm just gonna do ints, let's say zero to nine. It's exclusive, and I'll just print them. So I'll just use a quick method reference here. Of m numbers, zero to nine. Now what we also had available in Java 8 were methods limit and skip. So I wanted to get the first n elements of a list. I could just call limit, let's say limit five. And if I wanted to see the rest, I can use a complementary method, skip. These are good, but the problem with these methods is that you need to know this number in advance, which is often not the case. Sometimes you just know that you wanna keep taking elements while a certain condition is met, and you don't necessarily know how many there are before that. And that's exactly the functionality that was introduced in Java 9. So now we have methods take while and drop while, which are basically versions of limit and skip that take a predicate instead of an absolute number. So I can do something like this. Take while, step five and complementary method, drop while. So that can be pretty useful. Another useful addition to the Streams API is the method iterate. And we take a look at it. You can see that there's actually two versions of it. So the first one was available in Java 8. The second one was added in Java 9. And the difference here is this predicate here. So how is this useful? Well, let's take a simple example. Let's say I want to print all the even numbers that are less than 100, right? Even numbers less than 100. A very naive approach in Java 8 could be something like this. Going to iterate from zero, increment by two, then Streams are lazy. So I'll just take the first 100 numbers. So let's do something like this. And then I'll print them. And you can see that it kind of worked, but not really. And the reason that it didn't work is because I created an infinite stream here. And I did correctly filter first 100 numbers, but the stream kept going and at some point my integer went over and suddenly all my numbers were less than 100. And it's very easy to introduce a bug like this if you don't think about this carefully. And the interesting thing is that there wasn't really a good way of solving this in Java 8. And that's exactly the functionality introduced in Java 9. So in Java 9, I can replace this filter here with the predicate directly in iterate. And I can just do something like this. This is gonna work fine. And if you look at it, it kind of reads like a four cycle. And that's basically what it is. It's like a streamified version of four. So finally, a method that I wanted to mention that's directly on streams is a method of nullable. Again, let's take a step back of what we had available in Java 8. In Java 8, I could create streams of arbitrary elements. I could do something like this. What I couldn't do is something like this. Which makes sense, because you don't wanna have nulls in streams or collections for the matter. What I can do in Java 9 however, it's called the method of nullable that actually goes through nicely. But what it does, if we take a look at this stream, the stream is actually empty. So it didn't create a stream containing a null, it automatically interpreted it as an empty stream. So how is this useful? Well basically, if you're using streams heavily and you're used to sort of chaining many operations, you have many maps, then it's very likely that at some point you will end up in nulls in your streams and you will need to filter them out. Which means that at some point in your streams you will have to have an if statement in a block or ternary operator or some sort of condition like this to get rid of the results that you don't want. And none of these are really clean. So this essentially allows you to get rid of that extra null check and just make your code a tiny bit cleaner. So that's off nullable. The last interesting features in the stream API was actually in the collectors part. So collectors are the reduction operations on streams. So they typically aggregate elements from the stream to a result container and optionally they perform a transformation there. And there's quite a few of them built in the JDK. We can take a look here. And two of these were added in Java 9 and those are filtering and flood mapping. These actually work particularly well with the grouping by collector. So you might be thinking, okay, this look and sound very familiar and you're right because we do have a filter method and a flood map method directly on streams. And that's in fact almost exactly what these collectors do. They do the same thing that filter and flood map do but they do it on the side of the collectors instead of the stream directly. So how is this useful? Well, if we were in SQL world it would be kind of like difference between where and having as classes. So one of them happens prior to the aggregation, the other one happens after aggregation. And in many cases you can kind of simulate one with the other but there are a couple of cases where this makes a big difference. So let's try to come up with a couple of examples where we'll see this difference. So I'm going to construct a list of numbers here. I'll just do list. Let's say something like this. And so let's call this a list. And what I wanna do here is perform some sort of filtering and some sort of grouping to take advantage of the filtering collector. So I'm gonna filter the numbers that are greater than five and I'm going to count them by parity that's gonna be my grouping function. So let's try and do this in Java 8 first. So in Java 8 I would do something like this. I would convert this to a stream, filter the numbers that are less or actually I think I said greater than five. And finally I would collect them and when I'm collecting them I would simply group them and I would group them by parity which means something like this and then I would pass the results to a set for example. Actually I think I wanted to count them. Yeah, so let's do that. Yeah, so this tells us correctly that we have three odd numbers and no even numbers. Well it doesn't actually tell us that we have no even numbers, it's just kind of applied and the reason it doesn't tell us is because that information was lost. We filtered the numbers out before we got to the grouping stage so the grouping stage actually had no idea that there even were any even numbers in the stream and that's why the filtering collector can help us with this loss of information here. So in Java 9 I can modify this by adding actually I'm gonna remove the filter first and I will add the filtering collector here and I will filter the numbers greater than five and I must up somewhere, probably a bracket somewhere. Oh yeah, here we go. So in this case it actually tells us okay no even numbers and three odd numbers so you can see the difference here. Now let's try to do the same thing with flood mapping. So flood mapping is a bit tricky, we'll have to sort of craft the initially input a bit artificially to really be able to take advantage of this and similarly to flood map this helps us the most when we are dealing with nested collections in streams and especially if you have sort of duplicate elements it really points out the difference. So let's try to create some sort of a mapping like this. So I wanna have a mapping of things, two collections of things and ideally have some duplicate elements. So essentially I wanna have a multi-map that I would then convert it to stream but I can just start with a stream directly so I'll just do quick stream here and I will create a stream of map entries and I will just do let's say integer to a set of strings. Let's say something like this and I'm going to do a couple of these. Let's have some duplicates and finally something that does not duplicate with anything just for a good measure. Let's say something like this. So I have this kind of stream like mapping of numbers to collections of strings. So what I wanna do in my example I wanna go through the stream and aggregate the strings by the number that they're associated with. So let's try and do that again in Java, Java 8. Let's give this the name, let's call this entries. So it's already a stream so I can just call the method collect and I'm going to group this and I'm going to group it by the key. So for each entry give me the key and afterwards I'm going to extract the value. So I will use the mapping here and for each entry give me the value. And finally I'm going to aggregate this. So I've extracted the value I just need a container to put this into. So I will do something like this and hopefully I have enough brackets here. Yes, okay so in Java 8 I will get this sort of result. So we can see that these are correctly grouped by their keys, we only had two distinct keys and there's only two elements but we have all sorts of nested collections and it just, it looks at first sight like something that you should use flood map for. So let's try and do that in Java 9. In Java 9 I'm just going to change this. The flood mapping and this of course takes a stream and oh yeah I closed the stream before so let me re-initialize this. And you can see that here all the duplicates and nested collections have been nicely resolved. So two very small additions to the collector's API that can be very useful in some cases. So those are streams. Another very commonly used API in Java and again an API that was introduced in Java 8 is completable futures. Complatable futures if you're not familiar is essentially a framework for a synchronous processing in Java. So it's all kind of built around the class called completable future which as the name suggests is a future that can be explicitly completed so you can set its status and a value. And we have APIs for creating dependencies and sort of chain completable futures and that's how we model a computation. So we typically use completable future for a task in a bigger computation that consists of many tasks. The basic API as it was available in Java 8 is actually really simple. I can create completable future here. Let's say a future of strings and I'm just gonna call it CF. And then I can complete this future. Complete means I'm going to give you the value in my case is a string. So let's say something like this and then if I try to extract the value it's gonna give me the value it was completed with. So what happens if I don't complete it? Well, let's reset here and let's try to call the get method directly. And you can see that nothing happens. It's gonna keep blocking until somebody else completes the future from a different thread and that's sort of how we use this construct to synchronize things. So aside from completing the future normally I can complete it exceptionally. There's a method for this and that takes an exception. So I'll just give it illegal state exception. And now if I try to extract the value it's going to fail with the exception that I gave it. So that's how it works. You can complete a future normally. You can complete it exceptionally. So what's new in Java 9? Well, quite a lot actually. Completable future is a huge class almost 3000 lines of code. Many methods, many public methods as well. And in fact, many of these were added in Java 9. Most of them however are not too exciting. There's a bunch of utility methods, sort of factory methods and methods to support subclassing if you need to do that. There are however three methods that I'm really excited about and these are the ones that I would like to demonstrate. So Java 9 essentially introduced a new way of completing completable futures and that's based on a timeout. So in Java 9, actually let's reset here first. In Java 9, I can call complete on timeout which takes a value and it takes time. So I'll just give it five seconds. What happens here if I check it, it's not completed yet but if I keep checking at some point five seconds later it's going to be completed normally and if I try to extract the value it's going to say timeout. So this is useful if you want to wait to see if somebody completes it for five seconds but then if nothing happens you're going to provide a default value. So it's really useful in distributed environment. If you have microservices and you use completable futures for asynchronous computation and asynchronous communication between the services you can just wait for the service to respond but if nothing happens you will populate the value from cache or some sort of deflection like this. So that's completing normally based on a timeout. You can also complete it exceptionally based on a timeout. So let's reset here and I will call the method or timeout and that takes just time. So I will do the same five seconds and now we're going to wait five seconds. We can see that it's completed exceptionally and if I try to extract the value it's going to fail with timeout exception. So that's basically how it works. You can complete futures normally and exceptionally based on a timeout. So the last third method that I wanted to mention is a bit unrelated to these two but it also sort of has to do with default values and that's the method called copy. So copy essentially allows you to make a defensive copy of a completable future and this might not sound like much but it's actually incredibly useful if you're designing asynchronous APIs. So APIs that are returning completable futures because in this case you want to provide sort of one way synchronization. You want to give the client the ability to take the completable future and chain actions onto it, respond to the changes in the future but you don't want them to be able to write back to the future that you're using internally so you don't want them to be able to complete it. So it's kind of like a one way thing and that's essentially what the copy method allows you to do. So let's try and demonstrate this. I will just reinitialize and create a copy. Let's call this copy. Now we can see the original not completed, the copy not completed. If I try to complete the original, the original is of course done and the copy is now done as well and if I try to extract the value from the copy, it's gonna be the value that I put in the original. So that's one way. The client can respond to the changes in the original future. So what happens if I do it the other way around? Well, let's try this. Reinitialize the original, reinitialize the copy. Now I will complete the copy. And you can see the copy is completed but the original is still not completed. So cannot write back. And that's just, it's a really nice and useful feature. So these were kind of smaller additions to existing APIs that are important but I think it's time to talk about some completely new APIs in Java 9. And the first one that we had on the list was Stackwalker. So Stackwalker gives us the ability to easily, lazily and in a stream friendly way access Stacktraces. So just as a reminder, this is what we had available prior to Java 9 since Java 1.4 actually, we could create a throwable and call getStacktrace method on this and this gives us an array of Stacktrace elements. So if I try to print this here, this is my Stacktrace at this point in time. And this was okay but there are a couple of issues with this approach. First of all, it's very expensive. The JVM needs to capture the entire stack eagerly even if you only need the first few elements. There's no sort of convenience methods for filtering the stack. If you want to process it you just have to go through everything. You cannot obtain references to the actual class instances of the classes declaring the methods. Everything is a string here. And on top of that, you're not even guaranteed that you're seeing the entire Stacktrace. The specification says that the JVM can omit certain elements for performance reasons. So if those are the things that you need then you're out of luck or you were out of luck, power to Java 9. Because everything here is actually fixed in Java 9 in the new Stackwalker. So the new Stackwalker is actually pretty easy to use. I can just obtain an instance and call the main method there, which is method walk. And this method allows me to essentially treat Stacktraces as streams. So for each stream, I can just collect this, let's say to a list. And I forgot the bracket. And this is my Stacktrace. So it's very similar to the output that I got from the GetStackTrace method. But here, I can take advantage of all the stream like functionality. So if I was only interested in Stacktrace of step three, I can just use the limit method here. And that gives me the top three elements of my stack. Similarly, if I wanted to obtain references to the classes, I can just tell the Stackwalker to keep those references. There's actually a bunch of options. We're gonna use this one. And then I can extract that information. I'm just gonna remove the limit first. And I can use map for each frame, extract the declaring class. And these are all the classes involved in my stack. And now again, I can take advantage of all the stream's API. So if I was only interested in a particular class and see where that is in my stack, I can just chain a method filter here. And I'm going to filter for the util class there. So I will just do quick lambda. My class is equal to this class here. And you can see that there are two such instances in my Stacktrace. So really nice kind of little API for various specific things. And it's quite well done, actually. So the next API that I wanted to talk about, that's actually something that I'm really excited about. To me, that's probably the most underrated feature of Java 9. And that's the new process API. So if you're familiar with what we had in Java before, we had the API called process builder, which we had since Java 1.5. And it looked roughly like this. I can create a new instance of the process builder. I could give it a command, which is an external command that I wanna run in my operating system. I'm just gonna give it JPS, which if you're not familiar with it, it's a command that lists Java processes running in your system. And I can just start this. And that's pretty much all that this API allowed us to do. We could start for in processes, but that was about it. There was no way to get any information about the process, even really simple things such as the PIE. It's available here in Java 9, but it wasn't available before. So what people ended up doing is either using JMX, which is really hacky, or they would end up writing their own tools, which often involved calling something like PS and Grap. So we'd kind of use external operating system tools to get the information about your process from the outside, which obviously is really annoying, error prone, and it's actually really hard to do in a portable way. So it's great to see this functionality a part of the platform. So in Java 9, we can extract all sorts of information about processes through an interface called Process Handle. So I can, for example, obtain the handle to my current process and extract the PIE, simple as that. You can also extract all sorts of other information. You can see it tells me who launched the process, what command was used, CPU time, things like that. And there's convenience methods here to extract all sorts of information. Thing one that's going to be particularly useful is the method command line, which tells you how your application was launched. So that's nice. You also don't need to kind of limit yourself to management of the current process. You can get access to all the other processes in the operating system that are visible to you. So I can call the method all processes here, which gives me a stream that can extract some information from this, let's say for each process, give me info and command, and then I will just collect these. And these are all the commands running in my system. So really nice, very useful. A very useful feature of this API is also kind of a callback. So we're allowed to trigger an action when an external process completes, which is actually very nice. So let's try and do that. Let's try and construct a process with some predictable runtime. So I'm going to create a process builder here and call sleep. And I'll tell it to sleep for three seconds. And now I can just start the process immediately obtain the handle and call on exit. So on exit gives me a completable future. And we already know the completable future API, so I can just trigger an action when the computation is done. I will just do then accept. And I can just print the whole process handle. The two string method there is the PID. So just to recap what I'm expecting to happen here. A process is launched asynchronously. Three seconds later, the PID of the now DCS process is going to appear. Let's try this out. And here we go. So simple as that. And we also don't need to limit ourselves to kind of management of individual processes. You can create the whole pipelines in the sense of UNIX pipelines. We kind of connect the output of the previous process to the input of the next process. So I can just create a very simple pipeline here. Let's create a new process builder. I will launch my favorite command, JPS. Let's call this JPS. And then in the output, I will try to find JShell. So to find JShell, I will call grab and grab for JShell. And let's call this crept. And now to start the pipeline, I will just do process builder start pipeline. This needs a list. So I will take advantage of the new convenience factory methods. I'll just do a list of JPS and grab. And let's call this pipeline. And it's a synchronous. So nothing happening here. If I take a look at it now, it's actually going to say that everything completed. Everything completed successfully, exit value zero. So I can try and see what this process is actually found. So to do that, I'll need to get access to the last process in my pipeline. We're using X1 and open the input stream to its output. And now I need to do sort of standard Java boilerplate. And I'm sure everybody's familiar with, I will wrap this in an input stream reader and I will wrap this in a buffered reader. All so that I can call the read line method here and see that I actually found a process with this PID called JShellToolProvider, which is actually the process that launches JShell. And yeah, that's pretty much all there is to it. Just a really nice API. I'm super excited to see this as part of the JVM. And finally, it's not the kind of thing that you need to write yourself. So it's really good. And finally, the last thing that I wanted to cover here is the new HTTP to client. And the new client not only provides a much cleaner alternative to the old API, which was HTTP URL connection, but it also supports all the cool new things. It supports HTTP to with TLS. It supports a WebSocket, server push, proxies, cookies, asynchronous requests, basically everything that you expect from a mature HTTP client. The HTTP client is delivered as an incubator module in Java 9, which means that it's not part of Java SE by default. It lives in a special namespace. It can still change. And it's not resolved by default, but I pre-imported it into JShell so that we can play around with it. So just so that you know, now in order to demonstrate the client API, I'm going to need a server. And if there's anything that I've learned from giving live demos, is that you cannot rely on the internet here. So I'm going to try and write a very simple server in Java that we can use to test the client. So I actually really like this example because it's something that people usually think is going to be really hard to do or really complex in a language like Java, but you can actually do it very easily just with functionality available into JDK. And it's not even new APIs. It's all APIs that have been around for a very long time. So I will create the simplest possible server. So it's going to have one endpoint and no matter what kind of request is sent to that endpoint, it's going to respond with a fixed string. So let's start by defining the handler for that endpoint. So I'll do HTTP handler here. Let's call this a handler. And this takes an HTTP exchange and we're going to do a lambda here, a multi-line lambda, which is not good for readability. So don't do this in production code. And I'll just define a string here. Let's say, hello, Singapore. And I'm going to set the response headers on this HTTP exchange. So I'll just respond with 200, everything is okay and attach the length of my string here. And finally, I'm going to write the string to the actual response. So I will use tribe of resources and I will create an output stream, assign the response body here. And here, I'll use the output stream to write the string. And I have to do this for good bytes. This is an old API, but it's okay. And finally, close everything. So we take a look here. We can see our handler and looks pretty simple. Looks okay. So let's write out. So now we can create a server. So I will start here by creating a server and this takes a port. So I will give it, let's say, 8,000. And we don't need the backlog. And let's call this HS. Now I can create an endpoint. Let's say, slash hello. And I will attach my favorite handler to it. And finally, I can start a server. So hopefully the server is running now. Now in order to test that, we need to write the client. So let's try and do this with the old API first just to see how horrible it is. And then hopefully the new API is gonna look much better in comparison. So with the old API, I would start by creating a URI to my local server. So that's going to look something like this. HTTP, local host. I think I used 8,000 slash hello. Let's call this URI. I'm going to convert this URI to a URL just so that I can open a connection here. And this actually returns a URL connection, which is not what I want. I want an HTTP URL connection. And the reason this behaves this way is because this is a really old API that was designed with multiple protocols in mind. And even though realistically, HTTP ended up being probably the only one that's actually used. They didn't know at the time, so that's how it works. So to actually get HTTP URL connection, I'll need to cast this. And you can see that we're just starting out and this API is already really horrible. I'll just call it C. Then I need to set the request method here, which is going to be a get in my case. And that's passed as a string, which again, not very nice. And finally, we can try this out. So we can try and extract the response code. And hopefully, fingers crossed, we have 200. Okay, it's looking promising. So now let's try to actually read the response. So to read the response, I will turn the input stream on the connection. And here we go again, standard Java boilerplate, input stream reader, brought this in the buffered reader. And finally, call the method reline. And yeah, here we go. So both the client and the server work, but the journey to get there was quite painful, especially with the client side. So now let's try to do this with the new API. The new API is nicely separated and it's built around three simple classes. There's HTTP client, HTTP request, HTTP response, which should be pretty self-explanatory. So let's start by creating a client. I'm just going to create a new HTTP client. Let's call it a client. And by the way, if we take a look at the version here, it's going to say HTTP2. Now, to be fair, I'm not really taking advantage of this. I'm just talking to a very simple local server, but we're just using this to demonstrate the API. So this should be fine. Then I will create an HTTP request, which uses a builder pattern here. So I will just give it the URI that I have from before, call the get method nicely as a method here, and build it and call this a request. And finally, I can use the client to send the request to the server. And this also takes something called a body handler here. In this case, I'm just going to tell it to treat everything as string. Thankfully, there's a building handler for this. So I'll just use body handler as string. And let's call this response. So now to determine the status code, we can just do status code to determine the body and just call body. It's very nice and easy and very clean. It's actually really flexible as well. If I wanted to make this a synchronous, for example, all I need to do is change send to send async. And this, of course, returns a completable future. So let's call the response. Yeah, that's fine. And now, again, I can extract the value from the future and let's say look at the body. And here we go again. So very nice, clean, flexible. And that's it. The last thing that I wanted to show is actually kind of the first example from this talk. So if you remember at the beginning, we just used one plus one and evaluated it into JShell. And you've seen quite a lot of JShell by now. What I didn't mention is that there's an API behind JShell too. So we wanted to take advantage of this functionality in your application. You can code directly against the API. So let's try to explore JShell API a bit from JShell. So I will create a new JShell here. Let's call it JS. Now we have a JShell inside JShell. And let's try to give it our first example. So one plus one, this actually returns a list of events. I'm just gonna call these events for now. So if you remember, one plus one caused two things to happen in JShell. First, it introduced a local variable, dollar one, and then it actually computed one plus one. So let's try to check both of these in this inner shell. So I will take a look at the variables here. And this actually returns a stream. So I'm just going to print this. And we can see that we have a dollar one here. And now let's take a look at what it got processed to from the events. So I'm going to use the events, which again, it's a list containing a single element in this case that will just convert this to a stream, extract some information. Let's say for this event, let's take a look at the status first. And let's just print those. And you can see that it says valid, which means it was valid Java code, got processed correctly. So now if we wanted to make sure what kind of source code is associated with this event, I can just get a reference to the snippet and take a look at the source, but we know it's one plus one. And finally, take a look at the value. We can just call the value here. And you can see that it indeed got processed to two. That's pretty much it. It's actually a relatively simple API despite how much functionality is offered here. So feel free to check it out and play around with it. And yeah, this is kind of the list of my favorite APIs in Java 9. So I hope you enjoyed it. And if you have any questions, I'll be around for the rest of the evening. So feel free to come up and say hi. Thanks. And by the way, actually, before we go, I don't have slides, but I can save the output of this session and post it somewhere. So if you want to come back to these commands, you can just take a look here. And I will post it to where Ismar, here's my Twitter handle. So, yeah, thanks. Thank you. Dave, you are definitely the name of the classes. Why do you require an import from the nice piece of the audience? Sorry. For example, where you are using completion, potential, future, I have it. Yeah. You need to do the imports for these kinds of... Yeah, so I actually didn't show you that because I didn't want to waste time with imports. There's two things to consider here. So first of all, JShell comes with a set of default imports. And most of the usual stuff is there, all the core stuff, so a couple of core modules. But I also actually have a highly customized script here that I launched at the start. And I can show you that actually imports quite a few things just so that I can work with them without imports. And then I also set up an editor and stuff like that. For security reasons, it is possible to sandbox the show to prevent some kind of imports. I'm not sure. The main problem if I provide, for example, scripting using WebShell, integrating my web application, it's a security issue. If I disable, for example, Javio for writing on these, can they put in common, and so on. Yeah, so as far as I know, JShell just operates with everything that it has available in the JDK that you launched from. You can customize the JDK though. With the new modularity, you can select which modules you want to compile in the JDK. So I'm sure you wouldn't be able to accept the functionality after that. But it's kind of a workaround. I don't know if you can do it directly and just say, okay, don't import from these things. It's kind of more manned as a pro-diving tool rather than something that you would expose to a user on your system. So this is probably a general question. I haven't worked with the ACP libraries before because I normally use a framework or something that handles that for me. Yeah. Like how many, like isn't it mostly framework that you are able to do like it's free? Yeah, to an extent, like all of it, this stuff is just, you know, it's not new functionality. What's new about it is to have it done in a specific way in the JDK, but it's often about just standardizing what various frameworks we're doing before that, right? So, I mean, to an extent, yes. Like for example, the reactive streams, the Flow API, you'll probably never have to touch it because all the reactive streams framework are going to implement that. On the other hand, for example, the HTTP client or a completable futures, that's something that I use all the time because it's so low level that I just don't bundle library for this sort of thing. So that can be useful. And of course, language improvements would be in that category, too. I noticed the rebel seems a lot faster than the Scala rebel. Scala rebel often has like a little delay when you want to evaluate our system. No, like if there's some JVM trigger going on here or the... No, no, no. This was actually pretty sluggish, just based on the sheer amount of stuff that I'm importing. It usually starts within a second. And if I started here, it's going to take actually quite a few seconds to just put up, but that's just the imports. I don't know how come it's so much faster. I have no experience with it. It seems a bit faster than the Scala rebel. Sometimes the Scala rebel can do a bit better. I mean, Scala has, you know, that they have a different system as well. They might need to evaluate a lot of other things just because of the more dynamic nature of it. Yeah, there's a lot of type improvements that goes on there, right? And I think there's lots of times. So I would imagine that takes a lot of computational time, but that's what I was thinking. Okay, come on down. Cool stuff. Thank you. Thank you.