 All right. So it looks like we're ready to get started today. Hopefully you guys can hear me well and we got everything connected. I had to make sure to disconnect from the phone so we could talk here on the computer. But we're here for another definition. We're here to talk to Edson Yanaga. All right. So Edson Yanaga is going to walk us through Java, specifically a Java topic, and we're going to be talking about revisiting effective Java. So this is hardcore Java talk. He's going to do a lot of live coding. We hope the screen share is going to be working. So Edson, at this point, we're going to turn it over to you. All right. Hello, guys. I'm going to talk about effective Java. Of course, one of my favorite subjects. And there is a lot of live coding involved today, so I don't want to spend much time talking. So let's switch to the screen sharing. Yes, I hope you can see my slides. So yes, I'm Edson Yanaga. My Twitter handle is at Yanaga. Fun facts about me. I'm a Brazilian Japanese. I'm also a Java champion. I'm a Microsoft MVP and the DevConf Rockstar. And just in case you want to follow me, my Twitter handle is at Yanaga. I talk, of course, a lot about Java, DevOps, microservices, and other interesting stuff, at least for me. So let's go to the subject. Well, I don't know how many of you have read previous editions of the effective Java, but recently Joshua Block released the third edition of the effective Java covering the things that have changed since Java 6. So if you want to know more about lendas or even modules or something like that, you need to read the latest version of the book. And I think the effective Java was one of the most important books in my entire career, because this is one of the books that, oh, I think I know Java enough. I'm experienced. I'm a senior Java developer. But reading the book, reading this book, makes you very humble, because then you realize, well, maybe I don't know Java very well. Maybe I don't know Java enough. So that's why I'm very pleased to be presenting some tips from the book. And the goal of this talk is not, of course, to present to you everything about the book. I'm just going to pick some of the tips of the book, and maybe introduce some of my own tips. But this is an introductory talk. And this is just to encourage you to read the book, because I think it's great content for you to be able to be called yourself a senior Java developer. I really believe that you should be practicing most of the tips that are available in the book. But enough of talking. I think it's much more interest for me to show the code. That's why I'm going to switch now to my IDE. And here, let's start with some tips about value objector classes. So for example, suppose that the phone number is one of the entities in my system, and I want to make it immutable. Why would I want to make it immutable? We know that the hardest problems in the software development cycle is when you reach a bug, caused by some inconsistent states. And then this inconsistent state is caused because we have too much mutable methods in our classes. So we don't know exactly which entry point did the data got where the wrong data got into our classes. And one of the nice ways for us to try to minimize this problem is to try to make our classes immutable. I know that for most of the Java frameworks, it's impossible to make everything immutable. But it doesn't prevent us from trying to be as immutable as possible. So how can we do that? Of course, I could say that to make a class immutable, I could just say for the phone number, I could area code, and private int. Number, if I did these both, I could say, well, if they both are final, maybe then my class is immutable. So if the fields are final, then maybe I need a constructor. This class is not immutable because I can still subclass that and access the fields. And one of the ways for me to prevent that is to declare the class as final. But if you really want to make this class immutable, you just declare that as a private constructor. Because even if you subclass that, you won't be able to instantiate that. You're hiding the information here. So now my class is immutable. And if I want to have a nice way to be able to create instance of this class, instead of using a constructor, my favorite way is using static factor methods. So if I do this, a public static phone number off, for example, and I say area code, int number. Oops, nice typo here. I could say, return your phone number, area code, number. And why would I do that? You know that one of the things I don't like in Java is the constructor syntax. Because every time you want to instantiate a new object, you have to type like, for example, in this new phone number. And one of the downsides of using constructors that you need to know exactly the type that you want to instantiate when you're typing your code. So for example, if I want a phone number, even if phone number would implement an interface, I would need to know that phone number is the concrete class that I want to implement. And I would need to type phone number, new phone number. But what if, instead of doing that, we could delegate some methods, this knowledge about which type should I instantiate. And that's one of the reasons why we're choosing a factor methods. Another benefit of using factor methods that factor methods have a name. And constructors, you can give a meaningful name, for example. For instance, off, but if I knew that every time I'm calling this method off, I'm creating a new instance of phone number, I could call this method new instance. But since I want to have some flexibility, I'm just going to type off here and delegate this kind of knowledge to my internal implementation. Suppose that phone number has some very complicated computations whenever trying to create a new object. And if I want to optimize that, so instead of creating a new instance every time, I could, for example, implement the fly wave pattern. So if I could hear, well, if I could implement an internal cache, like, for example, an internal hash map. So every time I receive the same arguments for area code and number, instead of creating a new instance of the object, I would always return the same instance of the object, which is already cached. So it prevents me from executing the same extensive computation every single time. It also might save memory because if you're reusing the same values over and over again, you just have one instance in memory. And if I always have one instance in memory and not the benefit of that, is that if you want to compare separate instances, you can use the equals operator instead of the equals method in Java, which makes your operations much faster. So one of the reasons for you to use the factory methods, well, maybe I can use a fly wave design pattern. And another benefit of that is that you don't need to always return the same type of object. For example, suppose the phone number would, you would later specialize this class into international phone number and local phone number. But you want to keep the same class. So if I created this, I could say, well, if there were a code here is greater than 1000, then return new international phone number, which would be a subclass of this particular class. And I would have this flexibility of returning like subclasses of this phone number if I use a factor method. Or else, well, later, if you are using constructors and later you decide to specialize your class into subclasses, you would need to go through your source code and check every time somebody's typing new phone number. Well, in this particular case, do I need a phone number or do I need an international phone number or do I need a local phone number? So if you're using a factor method, you can delegate object creation to this method. So everywhere else in your code base, you can just change here and you don't need to change anyone else anywhere else if you want to add this kind of business logic to your code. So that's some of the things that you can do if you're using factor method. Also, one of the nice things that you learn when you're using effective Java is that you should fail fast. You should check in the values of the consistency of your internal state whenever you're creating an object and not when you're using that. Remember how many times we had that no pointer exception at runtime because, oh, this value was never supposed to be no, but yet it is and we have no idea how it came to this inconsistent state. But if our classes are immutable and we're checking the internal state whenever we're constructing the object, we'll never reach the inconsistent state in production. So one of the things that I could do here, I'm using, well, check arguments and say the area code needs to be greater than 100 and also need to check arguments that number is going to be greater than 1000, for example. And I'm just using this static method from the preconditions class from the Google Guava library. I'm not saying that you should use that, for example, Google Guava, but if you look at the source code, just if not expression from new illegal argument exception, which is the proper exception to be thrown if you receive an illegal argument. So you see you could be creating this library yourself if you don't want to add a dependency of Google Guava to your project. So I think this is a nice tip and approach, okay? So what else can we do with this phone number? Whenever you're creating an value object, you should be also implementing equals and hash codes. So if I want to implement equals and hash codes, if you read the book, you will learn that. One nice implementation of this could be, for example, if objects instance of phone number, then return, I can say phone number out there, receives object, have a cast, then I can see return objects, which is a method that was introduced in Java 7. This dots error code, other dots error codes and objects dot equals this dot number, other dot number, okay? Or else return false. So this is a very nice implementation. It should be correct. And also I need to implement hash code. A nice way for you to get the hash code of the object is again, this method was provided for us in Java 7. I can this dots error code, this dots number. These are very nice implementations if you don't care about performance and what's the issue here? You know, object dot equals, this method receives as a parameter an object. And we know that area code and number are primitive. So whenever I'm doing these, I'm using boxing to generate the integer and integer instance and then boxing and boxing, they're very expensive operations. So this is not optimized. So one of, if you know that this area code is a primitive type, instead of using typing object dot equals, you should be using this dot area code equals other code. And here I keep it this way just for you to know the difference. So if it's a primitive, you should be using the equals operator or else you can use object dot equals because they handle the special and complicated case that were well, first can be new, the second can be new, both can be null. So if you do is the object equals, it also has this logic, it's tricky logic inside this method already implemented and it's already on JDK, inside the JDK. So you don't have to worry about it or not. So object dot hash, again, this is a nice implementation of a hash code if you don't care about performance. What are the issue here is you have two issues. First, area code and number are primitive types and here I'm receiving a varrars of objects. So I have to box the arguments to be able to make the computation and I'm using a varrars. What is the issue here? Array creation is a very expensive creation in Java. So every time I am using a varrars, I have to create this array. So maybe here you could be creating, if you go to the, you could be using your ID, for example, to be creating your own implementation of the hash code or you could go look at the book and implement Joshua Block, suggest you this one nice implementation of hash code. So it's up to you, which one do you want to make, which implementation you want. But if you wanted to optimize this further, if I know that my class is immutable, so internal values will never change and everyone wants to implement the hash code because the hash code will never change over time. I can just assign here, well, maybe I could refactor this in a struct field. So I could say this, whoops, what went wrong? I could say private final into hash and this hash could be here. Hash you see this and I just copy paste here this code. Hash and return hash. So that's another optimization because we're only computing the hash code only once and just we're using every other time. Another optimization that you might use here for the equals method is that if you want to further optimize, you know that you're always comparing this instance to itself over collections. For example, you can just type this if objects equals to this return true another very cheap optimization if you're using the equals methods. So what else can we do in this phone number class? Maybe we can implement the two string methods and the two string methods, one nice implementation that you can use and what is the purpose of the two string method? Over time, people thought that, well, the two string method maybe it should reduce like for example, business strings. But actually the two string method is something that is useful for the developer. Suppose for example, that you're debugging or if you have a log statement and if you want to print some useful information for you as developer, well, that's what the two string method is worth for. So one nice implementation. In this case, I'm using Google Guavas implementation but of course you have like many other helpers for you. I'm going to use the moral objects and two string helper. Then if I add here, for example, error code add number, here I have a number and two string. This would be a nice implementation of the two string method and how does it look? So let me show here, I have phone number. Off, I'm going to say nine nine, three nine two three. And this one I want to print it. So let's try to run it. If I run this class, it's going to show me this string which is very nice because it's showing me that it's an instance of the phone number class and the internal state is error code nine nine nine and phone number is one two three, one two three. So yes, it's good. And you might be questioning me, well, then how do I show business strings? One of the less known interfaces of the JDK is probably formidable, which is the interface you might be using if you want to print business string. And why, how does it work? Whenever you have implement formidable, if you have format two, I strongly recommend you to read the Java docs because you have a lot of extensive documentation about that kind of flags with precision and the format are here. So, but if you want, for example, to internationalize the business strings, you should be using this class because we have all of the arguments and properties available here. But suppose that I want to print this phone number. I want to print the error code, a dash and later the number on it. So how do I use this method to print? I can use format or format two and I say that I want to print the first digits, a dash and the second digits. And I just type number, oops, the error code and the number. And it should be good. And just to show you the difference, suppose that instead of print line, I want to use this. I'll say I use a format or so print F. So the same instance, nine nine nine, one two three, one two three. And if I do this again and print, you can see that the result is very different. So here I have the developer, the string which should be used for debugging purposes or log statements. And here I have the business string, which is the one that should be shown to the end user in the browser or something like that, lack of reports. Okay. And what else do I need to do? Whenever you're using your internal state to compose a string to outside, for example, this business string nine nine nine dash, one two three and two three is going to be shown up to the user. So the user know that there is a difference. Like I clearly have an error code and a number. Whenever you're showing this difference in any string, you also need to provide a getter for these properties in your class. So in this case, I don't like providing getters for everything. I think you should be careful to think about the getters that are shown in your code. But in this case, they are required because I have a string that is using them separately. And why is that? If you don't provide the getters, developers are very smart. So whenever they say, oh, now I need the error code, but I don't have a getter for that. Oh, but whenever I format the business string, I have a dash separating the error code and the number. So very smart developers will do what? Well, they will get the business string, they'll parse it and will use the dash as a separator, then just to be able to get the error code and a number. But what happens later when somebody changes the business requirements and they say, well, now the phone number shouldn't be printed with a dash anymore. Now it should like the error code between parentheses, space, and then the number. Then everywhere where people were parsing your business string, well, now the code is broken. And worse than that, this is a runtime error because parsing strings is a runtime error. But if you provide the getters and setters here, nobody will be parsing the business strings. People will be using the getters and setters and people will be safe. You'll be able to change the business string without breaking the code somewhere else. So this is one of the things that I want to show you. And another thing that we could implement here, maybe phone numbers could be ordered. So I can implement the comparable interface here and comparable phone number and what changed it? Oops. What changed it here? I want to implement the methods. So how do I implement the comparable interface in 2019 using the 50 Java tips? So before Java 8, one of the ways for us to do that would be using the Guava, for example, comparison chain. So I could say comparisonCNN.start.comparethis.errorCode or that errorCode.comparethis.number. This is a very nice implementation like pre Java 8, but since we're using Java 8, we have lambdas and if anything else, we can do better than that. So I'm going to comment out this code and say that, well, comparator.comparingint, I could say that, well, I want to compare them using the phone number P and I first want to compare the errorCode, then comparing int P.number. And I want to compare this object with the one that I'm receiving. So this is a very nice way Java 8 lambda enable for you to implement comparable. So what's the downside of this? Every time I'm running this method to compare to, I'm creating a new comparator. So how could we optimize this implementation? I could just say that, well, maybe I could refactor this code and extract a constant. So phone number comparator. So now that it's a constant, they're type safe, they're thread safe. I can say phone number comparator.comparethis.no and this is going to be just be reused over and over and again, and this field can be private. Okay, I don't have much time left. So let's try to switch to another information for you. So now that we're talking about the comparator interface or the comparable interface, you know that with Java 8, we have a lot of functional interfaces and what is a functional interface? Functional interface is in the face that you can use as a lambda. And if you want to be very proficient in Java 8 lambdas, you need to understand all of the Java 8 function interfaces and last time I counted, I think there were 41 different functional interfaces and you might be thinking that is a lot, but you might have to learn all of them. If you learn just the six functional interfaces, you'll be able to cover most of the lambdas and how does it work? Unary operator is an interface that receives one argument and returns the same type. Binary operator is an interface that receives two arguments of type T and returns the same type. Predicate is a interface that receives one argument of type T and returns a Boolean. Function is an interface that receives one argument of type T and returns type R, which is very useful for you to convert one type to the other. Supplier is one interface that receives nothing and returns type T and consumer is an interface that consumes something. So receives type T and returns void. These are mainly the main function surface that you can use in the Java code. And one, an example that I can give to you is using enums. So enums is my favorite Java feature since Java 5. So what can we do with enums? So with the second edition of the factory Java book, we learned that we could create very nice polymorphic enum types. So for example, suppose that it's operation, I could have like add and subtract. And I wanted them to be polymorphic, like depending on the enum that I'm using, I could perform a different operation. So how could I do that? I could say public abstract void compute and I could say int x and int y and it's abstract. You should return an int here. And before Java 8, I would need to do this. Maybe I need to implement computer net and compute here on subtract. And here I could say x plus y and here I could say x minus y. So we'll have polymorphic operations between each one of the enums. But thanks to Java 8, I don't need to implement this ugly code. Now I consider it ugly, but before back in Java 5, it used to be one of the most beautiful implementation that could have in Java code. If actually I remember the day I learned about this feature in the effective Java book, it was like a weekend, money morning, I just was so anxious to be able to go today off and show off to my colleagues, oh, look what I know to do in Java. And show these, everybody's simply like amazed it. But this is a pre Java 8 way of doing this kind of polymorphic operation. What else can we do if we're using Java 8? With Java 8, maybe I don't need, this method doesn't need to be abstract. I could instead declare a field. Field, find out my int binary operator operator. And since the final field, I need a constructor. And since I have a constructor, I can say, well, return operator, apply x and y. And instead of doing this, what can I do? I can use a lambda in the constructor. So what I'm doing here, I need just to pass a lambda here, which maps to a binary operator. So this binary operator receives two arguments, x and y. And if it's an add operation, it's going to be x plus y. And if it's a subtract operation, then I can just do this, x minus y. Okay, and you might be also be thinking you can only do this kind of lambdas because your operations are very small, very simple. But if I have a very complicated business operation, it certainly wouldn't fit here in this lambda. Well, maybe we can create another class here, for example, suppose that I could create an operation called sum. And this sum operation will have like public static int, sum int x int y, return to x plus y. But since it's a business operation, it's very complicated, sort of will have a lot of different statements here and they would be very complicated. So lots of methods of business application logic here, but it still receives an int and two int, x and y, and returns an int. So this is a very complicated business operation. If I go back here, instead of doing this lambda, I could just call that method here, but I can do that, the matter than that, I can use a method handle. I can say, well, this operation adds the sum and it's going to use this operation here, which is a method handle, which leads us to the last subject of this talk, which are method handles, and for method references. So method references. This is an interesting information. Whenever, not whenever, but most of the times, whenever using a lambda, there's a shortcut for you to use a method reference if you're just calling a method in a class or an instance. And as a curious fact, in Java eight plus, you have five different types of method references and which are these methods that this types. First of all, you have a bounded. You have like, let me get the simpler one. You have a static method reference. For example, here, I need to get a function that gets a string and returns an integer. So if I can get in a string at the integer got parse int s and I'm returning an integer, but if I want to convert that to a method reference, I could say, well, integer, column, column, parse int, which once you get it used to the syntax is as much easier to read your code. Integer, column, column, parse int is better than here. So what else can we do? Suppose that I could also use the bounded method reference. And the bounded method reference, I need you to pay attention to because this is the most complicated method reference that we have. This one is receiving an instance and needs to return true or false. Suppose that I have an instance and I want to the instance.now.isAfterInstance. So this is the method that I want to implement. And how could I do this using a bounded method reference? And you know that my idea is not suggesting me to refactor to a method reference because these two lines of code do not buy the code equivalent. Instead of doing this, I could say, instance.now, column, column is after. And what does it mean? It means this particular method reference means that, well, I want to invoke this method now and this one is method is returning an instance. And on this particular instance, I want to call this method is after passing the instance as an argument. This is by far the most complicated type of method reference. That's why I wanted to emphasize this one. Next one, unbounded method reference. So I have a unary operator string. So if I have a string, I say string to lowercase. But the equivalent version of this using a method reference would be just to call string, column, column to lowercase. And the two last type of method reference are constructor. For example, here I need to create a new tree map. So I could say receives nothing. So I could just do this, new tree map. And it's a nice implementation. But if I want to use a method reference, I can just say column tree map, column, column new. Last one, array. This one receives a function which has an integer as an argument and return as an array of int. So how do I do I receive an integer? And I want to return a new int of i. The same thing as a method reference. We will use int, brackets, column, column, new, which is the method reference for, well, array construction. OK. And this is just the tip of the iceberg. The effect job has a lot of different tips. I'm sorry if today I had to rush because I don't have 30 minutes. But if you Google my name and this subject on the internet, I have a free hour long version of this talk where I discuss which are better-paced and much more tips which we'll be able to learn from. And, Burr, I guess that's what I have to show for now. Well, fantastic, Edson. That was certainly a fun session seeing you code all that stuff live. And that was actually a ton of chat. Very interested in this particular topic. But one of the key questions that I think came up and probably one we can answer right quick and then we have to get out of the session is what is the mapping of what you show to the chapter headings in the book? So in other words, OK, if I have the chapter headings of the book or the points of the book, where does that align to what you demoed? Where does that align to the topics you mentioned? Oh, right. If you go, I think I shared the slide deck link here on the chat. But if not, we can send later too. In the slide deck, I have the tips and the section of the book so you can follow up. Some of the tips I introduced to myself, but the ones that I'm using that are referenced in the book, they are available on the slide decks. So whenever I'm talking to the slide decks and say like constructor factor methods, I have a number in front of it. That number is the number of the section on the third edition of the book. OK, all right. Well, that's very good. And we are out of time today. I thank you so much for all your efforts. But to make sure we're here understands, we unfortunately keep these sessions very short so people can watch the video and kind of join us live and then we can get some Q&A in when we can. But otherwise, and there's actually another great question. We'll just go ahead and make a point out. Do you have any of this code out there in GitHub at all where people can just look at the results? Yes. And if you follow me on Twitter at Yanaga, I'll be posting the slide decks and GitHub repos so you can check the code later. OK, that's fantastic. So on Twitter, you can find Edson. And then thank you all for your time today. Edson, thank you so much. It was a fantastic session. I really love the deep dive into a Java-specific topic. Thank you.