The Good, Bad, and Ugly of Java Generics

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Hey, this is my professor! I should watch this. I enjoy his teaching style.

👍︎︎ 1 👤︎︎ u/Hoten 📅︎︎ Nov 19 2014 🗫︎ replies
Captions
alright let's get started welcome to the session on the good bad and the ugly of Java generics my name is ben Kitson from ano we're going to talk about just a little bit about why we would care something about generics then I'll get into several examples of looking at using generics and then as we progress we'll talk about some of the interesting features about generics and then we will talk a little bit about the the good parts and the bad parts and they do it to me the ugly parts as well so best time to ask a question or make a comment is when you have it so please don't wait until the very end just about any time is a good time and if you do have a question and I'm not responding to you that simply means you're not in my line of sight I'm definitely not ignoring you so wave your hands or draw my attention I'll be more than happy to heal to you and listen to what you have to say so let's get started we're going to talk about generics here genomics has been around for quite a while now we have that in Java those of you who came from C++ remember that we have templates in C++ and then of course after a while when Java came out Java wanted to make a simple language and one of the ways John became simple is by simply ignoring certain complicated features in C++ so oftentimes I would like to say Java is simpler than C++ rather than say Java is simple but as time went on we realized that we do want to have collections and objects that we want to be able to infer the type and it becomes kind of tedious but of course the first question is do we really need genomics and I have to say I really don't think we need it if you really if I were to talk about you know using generics I'm usually on the camp where I would prefer not to use it more than using it itself and one of the reasons for that is over the past several years I've been programming more and more with dynamically typed languages now I'm a person who programs it about maybe comfortably about eight to ten different languages some of my languages include languages like Scala which is statically typed but having said that I spend enough time on dynamically typed languages NSTAR SiC languages now that I don't depend on generic information as much as I used you now it really is about our comfort level if you're comfortable only programming in a statically typed language this feature can help you but if you're a person who is comfortable programming in a dynamically typed language it really doesn't add a great amount of value to what we are doing so the one of the things I want to emphasize here is genomics are not totally useless they are useful but let's not put too much emphasis on them and start designing very heavily with them and in the process let's not make things very complex you know in a way I would argue that genomics have introduced a solution to a problem which certain to a certain extent I would argue does exist in a statically typed language but for the amount of complexity that's been introduced in solving the problem you always kind of wonder is it worth it and if you look at the counter part for example what dotnet has done I would argue the dotnet has been a fairly good job in implementing generics and the reason is the generic implementation and darknet actually has a concept of reification which doesn't exist in job today but hopefully it will be present in Java 9 timeframe so we'll talk a little bit about that also and what the consequences of that are as we go forward so let's get started with some examples why do we care about this and what does it do provide for us I'm going to start with a fairly simple example by the way the examples I'm going to write here I will post them with it about let's say an hour after this presentation in my URL post this URL for you towards the end as well you don't have to write this down in a Harvey I'll put this up for you later on it's just down lit don't download link on my web site but it's not there right now but I'll post it within an hour or so after the talk is over so the first question of course is that why do we care about it what does it provide for us let's start with a simple example we are already used to this so I want to start with the array a list of numbers let's say this is the good-old the JDK 1.4 time frame right and then Java had collections of course and we could use collections back in there at the time and I have an ArrayList of objects and I'm gonna see numbers our ad let's say one and I'm going to start with a bunch of numbers let's say extremely simple bunch of objects right values and then I'm going to say I have a total equals zero I want to print this total out so I'm going to just say total here right now so of course I want to run through and do the totalling but you can see the problem already the compiler of course I'm using Java seven here is already giving us an a warning that I have some unchecked occurred uncheck the types that I need to really verify ignore the warning just for a few minutes so I'm going to say here I want to total up this so object and because a number in numbers so because the ArrayList is really you know doesn't have it's a rod type doesn't have a generic or parametric type I'm going to say total plus equals and I have to say integer and then I'm going to specify the number I'm interested in casting and I'm sure every Java programmer here has done that in the past and we have to do typecasting along the way and you can see that it printed the result but the code requires side casting now this is a fairly simple in fact trivial example and we can see the typecasting already here but you can imagine in a more complex situation the compiler kind of stands in your way and you're kind of screaming to yourself I know what this type is why can't you figure it out right it kind of becomes a little frustrating at the time and you wish the language kind of was a little smarter well actually it is with generics in a to a certain extent so rather than doing this one of the other problems here is that numbers dot add and if I say one point zero notice that we are not going to get a compilation error at this point so when I run this code you can notice that we actually are getting a one time error that the class not from the exception error by the way for those folks who are standing there are a few chairs here empty there's no reason for them to be empty if you want to come back here you're most welcome to come up to the front don't hesitate at all you're most welcome this is for us so feel free to come in and sit down there's chairs up here so so the real idea here is we're getting the runtime exception there's no reason for us to delay this to the runtime why can't we just you know notice at compile time well generics appear to be so this problem I'm using the word up here to say why there is a little later so so how do we go about fixing us so what I'm going to do here is to simply say that I have a list of objects so I'm going to say integer over here and of course back in here you would probably say integer to create this object and I'm going to remove this part for a minute but notice the benefit of this is we can say int number and we no longer have to do this typecasting and we can simply you know specify the number itself here and run it what a nice you know solution the warning is gone now if you're used to Java 1.5 and 1.6 you don't code like this and this was kind of a bit annoying right because you have to tell integer twice because you want to make sure your Java compiler really got it well that's kind of annoying you don't have to say that fortunately in Java 7 you can drop that part this really becomes more comfortable when you are dealing with like a hashmap when you have multiple types or even nested levels you can simply put an angle but of course you cannot leave out the angle by the way because you want to say that you're really interested in the type being you know inferred in this case and parameter type is used and not the raw type so that's still important to put that little angle bracket in there now looking at this code we may say all right we are better off aren't we well yes and no it is certainly better off because we did not have to type the typecasting and what most of us do in Java by the way we don't do this we develop IDE is to do silly things we have to do right so we don't need to depend on the IDE the language supports it but unfortunately though this code is really not any different from the code we had a few minutes ago it just it's a little you know you could say it's weak syntax sugar if you will it's not a live sugar it work equal that you get in the shop right it's not even a sugar in that regard so the reason why it is like that is because you didn't really remove the typecasting you just hid it if you're not sure about this let's take a look at this for our second and Java P minus C I'm going to run and I'm going to run run it with the options and I'm going to look at the sample right here that we have created and let's take a look at what we have under the covers I'm going to go to the main function because that's where we wrote this stuff so let's go to main and I'm going to look for the little famous check cast as you can see and therein lies the problem as you can see right there so the compiler is still doing the check cast under the covers and it's then calling the int value for s so rather than we doing this step we relied on the compiler to do it so in a sense we didn't do anything different but but the real benefit is we didn't have to look at that you know vomit if you will and in our eyes the vomit is kind of hidden under the covers and we don't have to be doing the casting for ourselves not a good thing to talk about right after lunch but sorry so that's example of how we didn't really remove that but still it's happening under the covers right in fact this is a little bit worse than that because even that runtime exception is not fully gone for example now we'll see how that is a little later we will not talk about the back parts right now we'll just focus on the good parts for now we'll come back to that a little later and see so we saw how we can use generics and all that it gave us right now is the little casting we didn't have to do and then I gave like I said I'm not going to completely throw that out I think that's still a benefit because it makes our lights a bit easier when you're writing code we don't have to be doing the casting and certainly there's benefit to that um but then again when we talk about generics we can talk about generics in various levels let's say for a minute that I'm interested in creating a generic method instead of just you know using something else so we could write a for example a function and I'm going to simply say output okay to say that our code is working for most part generics are about interfaces right the way to work with classes and casting them so I won't put too much body in the code we'll play with the interface of the methods for most part here so I'm going to write a method called copy let's say and this copy is going to take a list of number numbers or whatever it is from a source and it's going to copy it into a target will call it as destination right our target is a better target so so here's a function of go-to right called target so but notice the type T now you say how does it know that this is really a parameter type well we know that when programming we should not use single letters for most of the things right I mean you would agree that creating a single letter class name is an act of criminal negligence right nobody should really do that right so you can argue that's kind of obvious what des but of course life is not that good we do have people creating things like that so you want to clarify what that is so you can simply say P is the parameter type over here and and you can specify what the return type is in this case void or you can say T if it's one return type T itself so you can see how it was easy to write that but there of course one of the things I want to do here is we have a parameter type meaning we don't have a clue what we're going to receive in this case and only requirement here is the list of type of source should be the same as the list of type of the destination in other words if you have dogs on one side it should be dogs on another side you can put cookbooks in water dogs in another fair enough but then I want to say I don't want to copy elements if they already exist so I could say if target dot get and let's say for a minute I'm going to keep this trivial so don't get let's say is comparable comparable to and I'm going to say source start get and I'm going to say if this is not equal to zero don't worry so much about the correctness of logic here like I said I'm more interested in the interfaces of things so all that I want to do is for some arbitrary reason I want to compare the two objects in this collection well you see the compiler kind of looks at the same size huh what does that mean really if it bars that does it say is how do you call compare to what does that mean right it doesn't have a clue because not every object in the world has a compare to method so as a result it says I'm sorry I cannot work with you on that well this is where what we can go a step further is to say hey I'm expecting a type T or right but that type T is going to be extending from a comparable interface in this case I'm specifying what the type should really be in this case and you can specify some of the details about it so basically the idea really here is compare a compare to right so compared to so let me get back to that error that I messed up a few seconds ago so let's get back to this to say that it really is complaining so right then it's complaining and I put this little comparable extends and it's okay right now what are we doing really here so what I'm saying is I'm telling the compiler all right let's be a little bit more restrictive here I do want this to be a generate type I want to receive some kind of arbitrary parameters but I really cannot be effective if I really don't control a little bit about this and then the worst thing we could have done is we could use reflection here but that we kind of suck isn't it so as a result what we said was we said the extends comparable T now don't take the word extends as inheritance in this context that's really not the meaning here what this says is that the type T derives half of either through inheritance are through interface inheritance or class inheritance doesn't mean that this is capable of supporting that methods that particular interface or class is going to support so this allows the compiler to kind of do a little bit of time checking and says all right all right I will accept anything you send me that has that particular implementation so for example if I go back here and call the use method this time sorry the copy method this time and in this case I say copy and I want to send list1 and list2 over here as parameters and what can these lists be well actually make this a little bit easier for ourselves now that I've said extends actual let's continue with the sorry so I'm going to simply say integer here for example list 1 and I'm going to call this list integer let's say list it too and I'm able to call these two guys here and send it right this one and list two probably they say renew ArrayList there we go so I could send this type over here and it's going to be fairly happy with it why because we know that integers support the compare comparable interface and we should be able to send it it bombed on is here because of this function doing some stuff but the interface really says I'll accept it but on the other hand if I were to change this to a sample and a sample which is the class in which I'm writing the code notice that in this case he's not happy this and that's because our class sample doesn't implement the comparable interface right so it emphasizes that and checks for that also very easily we can see that very very nicely so that's basically what we are doing here in this example is do you know let's take the type information for us so we can decide what you use so we placed constraints on generic parameters but we can also create classes which have generics as well so how do we go about creating classes with generics so in this case for example what I would like to do is simply create a little example class let's call it as a list class so I'm going to say my list is the class I want to create but I want this to be a parameter type to class so I'm going to specify an angle T to specify what the type is of course if you want to have multiple parameters you could say angle T comma E and can give other names for these collection types are parametric types rather so in this case I'm going to provide a method called add which takes an element as a parameter and again I will simply say adding over here so we can check that it's calling this so I'm going to create a my list over here of integer if you will and in this case I'm going to say list equals new my list and we can use the angle to infer the type and then of course I could simply say here let's call the list start and in this case to run this let's start ad and I'm going to send the one to it you can see that's a happy with it but if I say let's start ad 1.0 the compiler should I get complain to a saying it cannot accept a 1.0 because the type is required to be an integer type and you can you can see that it's emphasizing it so again creating classes seems to be fairly simple but don't don't get led that you know give you a false solution I'll talk a little bit later where it's not really that simple as we think it is and I'll show you some examples where we have to be a bit more careful about this but this leads us to something else we need to worry about when we create classes the next thing we get into is of our inheritance with classes so we can use inheritance in normal classes right you have a class based class you to write a derived class which extends from the base class and anywhere an object of the base class is required you can send an object of the derived class you say that sounds like a great idea how does that work with generics and especially generates and collections how does that translate to there is an interesting principle call Allah scoffs Institution principle it's one of my most favorite principles because the scoffs attrition principle says that if you're using inheritance we should use inheritance only when there is substitutability in fact using inheritance for mere code use is really a bad idea now one of the reasons why we normally don't use anything else but using happens more often in Java is because inheritance is so easy to write in Java right now if you read good object into design books they talk about how delegation is much better than inheritance itself now most of the time you would be reading this book on yes yes absolutely correct it delegation is much better than inheritance and you close the book and roll your sleeves and start using inheritance now the reason why we do that unfortunately is because we don't have a clue how to use delegation in Java right and and if you notice how to really type it becomes really hard I'll talk about delegation and in one of my design patterns talk I know tomorrow or day after but but we can't really do that much in Java itself at least not not yet so what do we do we normally use inheritance well inheritance except should be used only when we want real substitutability if you only want code reuse and not substitutability meaning you don't intend to use an object of a certain class in the place of another object of the base class then you should not use inheritance or we should not use inheritance well let's take a look at an example of this and see how this manifests itself let's say I have a class called the fruit and and I have a class called banana and to keep the example very simple which extends from fruit and I'm also going to have a class called orange which also extends from fruit now what I would like to do is just to kind of make sure things are working the way we should use it let's say for example use fruit and I'm going to take a fruit as a parameter I'll call it as fruit and we will simply print out the fruit fruit of fruit we received here so we'll say received and let's go ahead and print out the fruit over here cool now of course I can call this method fairly easily but to do that let's create a banana object and here is our banana object equals new banana and I'm also going to create over here in orange object so orange a say orange equals new orange and I can call this method right so I can say use fruit and simply call this with a banana object and a you know orange object of course this is kind of trivial but we want to make sure that inheritance works today like re so but what about using a collection let's try that for a second so I'm going to say public static here and we'll call it as use fruit basket and I'm going to take a list of fruit as a parameter we'll call it fruits over here I'm going to simply output received one more time and this is going to be fruits so what can I send to this obviously I can send a collection of fruits do this particular method let's do something here let's create a collection of fruits over here and I'm going to say basket of fruits and equals what is this going to have in this case I'm going to simply say equals our ArrayList of of course floats now I'm going to say basket of fruit start add let's put the banana in in the in depth fruit basket I'm also going to put a basket of fruits over here and add let's say orange to it so notice my fruit basket contains a collection of objects of different type but those inheriting from the fruit itself I'm going to send this and say use fruit basket or use fruit what did I call use fruit basket that's what I'm calling it here so use fruit basket I'm going to send the basket of fruits to it and and notice in this case is happy receiving it right yeah not a problem but imagine for a minute that I go back to this code and in the used basket of fruit I'm going to take this fruits basket and I'm going to add a new orange to it so I decided to receive a basket but to add by putting an orange into it right and at this point is that a problem not really right because we created a basket of fruits we send this object to this function and when it comes back it comes back with one additional fruit I don't think that's the problem I can print out what I have here and you'll see there's an orange back to you and you're like I like this method it gives me back some fruits extra fruits right that's nice but let's change this a little bit further now I'm going to Institute of this change this to basket of banana right there and I'm going to call this basket of banana instead of basket of fruit and now I'm going to simply add the banana to it nothing else now I'm going to call the basket use fruit basket but I'm not going to send a list of fruit anymore I'm sending a list of banana what do you think is it a good idea or not no right in fact if you're sending a basket of banana right now you're going to be surprised when you get this basket back to you you're like whoa how did that happen right this is only supposed to have you know bananas and it had an orange come up with this you say Weinke that's not a problem we have this wonderful thing in Java called exception handling right I mean we all know that so much so within the function called you know use banana a fruit we could check warp this basket is and if this basket cannot accept the orange we could have told throw an exception what do you think of that idea no you will not have friends that work if you do that right they're not going to really like you one day somebody comes to your company and says who is this guy eating there alone and then you know why you're sitting there alone and eating right so such kind of interface building is not going to help you know build friends and companies why because it's close are surprised at you you have established a contract in this function that you can call this function and suddenly you're saying I'm going to start throwing its abuse on this function and this really makes it very difficult to use this function in our code you don't want to go that route alright great so we don't want to do that and when does the compiler help us here how beautiful that is it tells us don't do that right so ever cannot well actually in this case of course the error is because of this optic but let's go ahead and change this over here to vascular banana obviously but when I go back whoops I need to be consistently changing this guy right refactoring need to have a 2/3 factor that so notice what it does here it tells us method use through basket in class sample cannot be applied to the given type it is I'm expecting a list of fruit you cannot send me list a basket so in other words let me rephrase what what we are seeing here we know that banana inherits from extends from fruit but list of a banana does not extend from list of fruit so keep that in mind that you cannot just use a collection of the rive type in place of a collection of base type because if we arbitrarily do that we will leave we will get into trouble with our code so it protects us and says don't do that it doesn't allow us to do that so that's a good thing now we saw how the compiler is helping us here but I'm going to go to the quite opposite and look at a case just now so what I'm going to do now is to twist this problem just a little bit so let's go back to this code let's get rid of these functions we don't need them anymore and I'm going to write a function called copy and what copy is going to do is take a list of types over here I'm going to make this very generic type and let's say T over here so this is going to be a source a list and I'm going to provide another list here we call it target list so there are two list of topics over here a list of collections over here and when we come back to this in a minute how we going to use this we'll come back to that in a minute so I'll leave that empty for now so what are we going to do in this endless function so I'm going to have a banana an orange on hand and I'll have created a list of fruit for us for ourselves and I'll call it a basket one and equals new ArrayList of just the fruit itself so let's start with that and to this basket one I'm going to go ahead go ahead and add over here let's go ahead and add a billion and we'll also add an RINs to the sky so so we'll add an orange to this so right there are orange and banana in this particular basket now I want to create another list so we'll call this as basket - if you will and this basket - is going to contain the copy of the data that we're going to create so in this case I'm going to say copy and let's say basket one is the source and basket do is the destination and when we are done we will print out what's in the basket - how many elements are in basket - it better have two elements in this basket when we are done of course I've been implemented the code yet so let's go ahead and implement the code very simple here for and we could say type element in the source and we could simply say in this case target dart add and then the element itself so this should give us two elements in the object when we are done so we can see how simple that was right great now let's go a little further here and I'm going to create a basket of bananas right now not a basket of fruit so obviously I cannot add an orange to it but I just added a basket up in in and added orange to it then I create a basket of fruit and now I want to say copy the bananas from the basket of bananas to the basket of fruits what do you think should there be a lot or not well I'm not asking will the compiler all over it or not I'm not asking that do you think mmmk more about you than the compiler do you think it should be allowed or not yes absolutely you said no go play with some fruits tonight absolutely right because you have a basket of fruits and I give you a basket of banana and I asked you to transfer you can trouble some employee at work I think right if you refuse to do that so you take bananas from the basket antennas and put them in the basket of fruits what's wrong with that I mean that's legal guys that's perfectly fine right so absolutely what is the compiler thing know the compiler says I'm going to protect you in this case right so when I run this code compiler says cannot be applied it says I need a list 2d mr. t both of those should be exactly the same type i will not all of you to do that in in other words what's kicking in here the Liskov substitution principle right because it's worried that this may be a wrong operation I'm making sense a few minutes ago I showed you where this is good now I'm turning out and saying it's not good all the time so what you want is that override switch saying thanks compared about no thanks I know what I'm doing here right you want that override switch to be clicked on now let's consider a couple of options here one option I can think of and you should probably stop me when I'm thinking about it used to say comma X and change this to a type X I won't even try to compile it what do you think of that idea terrible idea right why because you suddenly start putting bananas into a you know a basket of books and that all gets squishy it's not a good idea right not not not something you want to do so what do we do here well you are kind of reasoning and saying all right let's think about this direction of copy if I have a basket of specialized I I can take special eyesight from it but I can put it into a basket of generalized type the base type but the other way around is not valid right in other words you cannot take a basket of any fruit and then grab one arbitrarily and put it into a basket banana that's not allowed so in other what you need to think about the direction that you're going bananas are okay in a basket of fruits but an arbitrary fruit is not okay in a basket of banana so in order to do this this is where you gotta kind of scan at this for a few minutes to think about it you're saying I'm going to accept some time where that type superbee meaning that P that you specify here appears as a super type of that type so in other words you are saying I'm going to receive a source whatever that source is I want to receive that source and the type on the right side either is a type of that source itself the source type itself or it could be a type which is a base type of that type right so in this case if this was collection of fruit this could be a collection of fruit as well but on the other hand if this is a collection of bananas this could either be a collection of bananas or one of the base types meaning a collection of fruits as well so in this case we sit super remember we said extends a few minutes ago here we are using super in this particular case to run through this and you can see it did copy and work just fine like a charm go ahead please know this would be this is possible in almost any version that supports generics you can use that in previous versions as well okay please but bring is better with you oh no no so the answer is if you notice what we did here we started with the basket of bananas the left one is basket of bananas that's the source we are copying from and we are copying into a basket of fruit it's a basket of fruit with only bananas which is perfectly fine and I can then take it and add more fruits into it later on but it's perfectly it's perfectly okay for a basket of fruits to contain only bananas but it's not okay for a basket of bananas to contain anything else so so let me put it this way how do you say this a basket of fruits which only contains bananas doesn't become does kind of bananas yes the return type of what this function itself doesn't return anything it's a void function yeah yeah no yep umm all right so the question is could this so the shoulder source type be super tea and and the answer is not in fact this is where it gets a bit tricky that's a very good question by the way and this is where is that you have to sit there and stare at it for a few minutes because if we put the information in the wrong place it may appear to get through the compiler but has consequences later on so we got to be very careful in selecting the other question people normally ask is should I say question since tea on the source side again these are extremely tricky things we got a reason through and figured out what makes sense because the goal here is not to get something that's you know extending from it you want to say I would accept the base type in other words you have to really clearly set the frame of reference for you and say if this is the basket of fruit what can I accept if there's a basket of banana what can I accept you got upset a frame of reference very clearly on one thing definitely really good questions but unfortunately you got to really reason through them and you cannot just rely on the compiler alone to decide this excellent so we talked about how we could use the wildcards and then specify the restrictions and I think we are almost done with the good parts of the back part it's downhill from now on so we're going to talk about some of the bad parts of generics now the the nice thing about generics is it really makes it easier for us to write code we don't have to deal with all these casting and all of that but I want to emphasize let's not put too much emphasis into generics in other words if you wake up one morning from bed and the first thought in your mind is generics are cool call your boss and say I'm sick today I'm not coming to work right that's not a good thought to have right because they are not cool they are just solving a problem that barely exists but it's really a complicated solution for that so so for all the complexity it introduced as you can see you kind of wonder how much benefit it is because to avoid the casting we are built around such a complexity around it the other thing I will also emphasize this don't get me wrong I'm a huge fan of compiler support I like languages like Scala and sharp in the dotnet word that enhance know for example that give us all those benefits but unfortunately we got to realize whether we are going on the compiler doing a good job or a compiler doing the poor job of static verification which doesn't really help us with tight you know emphasis in a great deal that's where it gets very tricky so given this let's talk about what happens to generics now unfortunately all generics go to the compiler to die and when the minute the compiler sees the generic it completely he raises that off now you may say why do they do that now I'm very sympathetic to this I want to be fair when I say this and I don't want to take this an insult on the language or the compiler but the problem with Java is the previous versions of Java right and the problem with Java is its success and one of the problems with Java is they want to provide backward compatibility now it is extremely hard problem to solve if you don't provide backward compatibility you're doomed and if you provide backward compatibility you're doomed so that's really the matter of the fact so you really have an option to know which way you want to be doomed so I think that's not a bad thing if you can really look at it that way right now in the dotnet front they really decided to break the backward compatibility to a certain extent and they full pores went with generics and they have done a fairly decent job and if you look at you know five six years later that works really well but this is a baguette way of caring with Java now of course it really comes down to a very fundamental principle behind languages and I respect that certainly right if Java's fundamental principle is to preserve the enterprise and not break backward compatibility I think we should just accept that and live with the consequences of that because at some point we cannot have the cake and as it eat it right so we have to be you know careful about this but having said that let's take a look at what tightly ratio really means what does it really do for us unfortunately if you go back to this code let's take a look at this example here and let's for a minute let's say I want to create a public void let's say a static void and I'm going to say use and I would say instance one and instance two so I'm just going to create this in a little function and I'll just call this a use call again remember we're really interested in the interfaces of functions not the implementation so we don't have to care about what these functions do under the covers so now I want to use this function how would I call this function so we could simply call use with maybe one and two here as parameters and say use call and just call this function we have to say that this parametric type we say it's a parameter type and we saw that use what's called now you look at this and say all right so what does this T really that we have here the parametric type what does that really mean so let's go back here and look at the java p and take a look at the disassembled by code one more time and if you look at this line you're going to be excited you're going to say how look how wonderful that is it says u s-- t and it's a s t and t how nice that is well unfortunately the real stuff under the covers is this so it says that this function signature is an object in an object right so it really kind of say is a let's discard the type information here that's called type eurasia this is one thing i love about our field we can do evil things but give really beautiful names to it right and it's a caller type eurasia like I described it good right it sounds nice well it's a pretty bad thing it because please said all therefore you put it I'm going to throw them away we don't care about types at this point because we cannot handle it this is fundamentally the difference between type erasure and type reification a pipe verification is where you take a generic type and you make it very concrete and say that itself is the type and in Java we don't have reification at the genetic level Dartmouth has verification right now some of the other competitors have reification but Java is working towards it so eventually we will have the reification right in job but the point really in this case is that we are using a pipe Eurasian but don't assume that you will always get a type object right it would be that simple would it no you have to actually examine this a little bit to know what the type is going to be so let's take a look at an example here further so I go back to this example here and say hey but I want to say that this guy extends from comparable API so I'm going to say comparable T over here so now we have said that this T extends comfortable T of course since one and two supported we can easily send that over there to an ecologist for the audio here so so basically in this case what does this mean then if you take a look at this now can notice well actually these there are difference not yet so in this case I'm saying that this would be extending from comparable T so in this particular case it should say I want to go ahead and change this to there we go so I probably did run the code let me see if that really compiled it again yep there you go so notice in this case it said I'm going to replace this with comparable type rather than object so in other words it doesn't erase it to object all the time it simply erases it to whatever time is the least common denominator it can think off at that point and in the case of references it's an object ID but in the case of other types it could probably decide what the type is based on the common type notice also it's comparable and not compatible P at this point so just keep that in mind as well so alright that's great but one of the things we can also do is we can specify multiple constraints as well so you can put an end person and say serializable for example right r cloneable for example and you can specify these types unfortunately if you specify some of these constraints what you would notice in this case is is it serializable one of the two that input support I'm not sure exactly what it supports but anyway whatever type you put here unfortunately what will happen is it will simply ignore that again and the erase type will be the very first thing you specify in there in this case the comparable is what is going to become the erase type so to be careful about what type is going to manifest itself by the way if you're not sure about what type it is you are real friendless Java P Java P is a fantastic tool it's a great tool to use on Friday night when you're alone and don't know what to do like it gives you really good company so open up in Java P look at the bytecode the streets you know around you are much safer for a few hours at least as you're looking through it so absolutely take a look at what's under the covers and find out what the type really is and you can kind of get a feel for it so absolutely if you're mainly not sure drill down and look at the Java tee and take a look at what what it contains so so IB racial kind of we saw the effect of that right there but what are the cons because of doing that well it really boils down to you quite a few surprises now of course you really have to sit there and think about some of these things because otherwise it surprises even worse because you normally learn this in odd ways and and that those are not fun so when it comes to using generic types we have to do a little bit more deep thinking and trying things out and we cannot just say oh put the type in their file type in there and it's done so let's talk about some consequences of this the fortune for most consequence which kind of makes me sad a little bit is that perogative tribes cannot be primitive types and it should be kind of obvious what the reason for that is given the type of Asia problem we saw here so for example if I go back to the code and I said you know what I just want to send a one and two after all so why can't I just use parametric type of integer itself so if I try something like list of let's say let's get rid of this guy for a second if I say list of you know int over here and list equals new array list of int we're going to get really complained that because we cannot use primitive types in this case it's gotta be in a type class type in in other words so so Java as much as it's object-oriented really is not fully object-oriented right because Java still has two classes right the primitive types and the object types and and genomics are in parametric types can only be object types not the primitive types per se so that's one big restriction we have to live with in the case of Java the other thing is we cannot instantiate the parametric type and and for example let's say you're creating a parametric method over here public you know let's say over here some type doesn't matter what it takes and I'm going to say use and in this let's say we have a parameter type instance and maybe I want another instance of this type so I decide to call nu T like this and notice we gotta ever saying we cannot create an instance of that type now you say why can't I create another instance of the type and the reason is remembered because of type II ratio it doesn't have a clue what P really is I mean you would be in this wonderful assumption you will create an object of banana and you end up getting object of object and they're like what good is that right and you kind of taste in it it tastes really weird and that can be very surprising right so you don't want that definitely so it kind of takes a primitive measure and says well I'm not going to surprise you that way I will just not make make sure you don't create it so you say well wait a minute but if I do want to create objects I mean lost completely no you're not what you need to do to get around this limitation is you would have to pass a class type into the into this and say use the class type as a factor me to create the object in other words you can kind of have to use a repeat of reflection layer in there and say send class angle T and you say metal class and then say based on the middle class create an instance and you could use the correct ways so the right so the question is kids the sorry yes I am I am a boy yeah I am what was the question oh okay so so the question is can I send enough information to be like extend something and in that process can I do in ut this is one thing I love about Java programmers they have relentless hope this is amazing so sorry and the answer is I had similar thoughts to you I'm not putting you down at all in this because a lot of times I get excited like can I do this right and usually it's the middle of the night I'm screaming I cannot do it and doesn't really have the children when I'm in there ah but the point really is no the reason is know why because remember one more time if you were to specify that constraint whatever that be it still uses the least common denominator and the chances are you say create me a banana it is a creating a fruit and if that was not abstract class you will again get incorrect type in this case or who would want an object of comfortable anyway that's an interface right so so unfortunately well it's a wishful thinking it is good thinking unfortunately the mechanism Buddha us to do that because we don't reach for enough to really control that excellent so so we saw how their type information kind of restricts us there's another problem also we have to be careful about for example let's say we have a class called let's say an interface interface called event and the event is going to take some type of event and it's going to give it to us it's an interface right I could have an event of string type it could have an event of a couple I could have an event of something else who knows what the message could be in this event could be given to us so I have a class called my class and this class implements the event of type let's say string and that's what I want to receive in this case from this code so if I were to go call this little code just now let's make sure this interface is good so we'll simply say ok for now and when I run this it says I'm fine but what if I say not only can I have a event of string but I could also support an event of integers for example and notice we had in trouble right now and the reason it's is it says hey you cannot have multiple implementations of the same interface obviously in Java you wouldn't say implements you know I won't come I want to implement the interface one twice isn't it so it doesn't all of you to do that and because of type erasure these two guys end up being the same under the covers now just a quick distinction in dotnet there is a concept called you can actually do interface implementation either directly or you can also implement direct interfaces to say there's a method coalition you can handle that as well but unfortunately Java doesn't have the concepts to handle there and as a result the interface implementation is pretty straightforward in Java and you can't really push that to any further extend so there's no real classification you can give to say I want this to be this other implementation you cannot specify that in this case so so if you can really you know control that um there is also a problem and this is a little bit shocking because the problem there are two problems that you wanted to solve remember one is to get rid of those vomits in the code where we constantly casting to a certain extent I would say that has been resolved but the other problem is to avoid one-time exceptions and catch those problem in a compile time unfortunately that is not entirely gone and the reason is big because of backward compatibility you would argue this is not too bad because the compiler can still work as but let's look at an example of this real quick so what I want to do here let's say for a minute that I want to pass let's say I create an object of list over here integer and I say numbers equals new ArrayList and in this case I'm going to simply say numbers dot add one and and just deal with that now let's say total equals zero back to the example I started out with and I'm going to say in number in numbers and I'm going to simply say total plus equals the number given to us so this was the problem we started out in the beginning and we said look it's really avoiding us to have to really do conversions that casting of course if I had a bunch of other values here we could use those and and certainly that makes life easier but what if I said numbers dot add 1.0 well the compiler immediately jumps up and says no you can't do that because 1.0 is not the type I'm expecting here so that's a good thing but what if you had a function somewhere that was receiving a ArrayList this is like the old implementation that you had and for backward compatibility you want to call into that function so I'm going to call a function foo well in programming sessions you have to have something called foo otherwise the talk is not done so I cleared that checklist so I want to send the numbers over there to it right so I'm going to send that to this function foo how would I use this function foo so we could write this function foo here so let's say this function foo really takes a list of numbers we'll call it numbs over here and and so I'm going to pass it to that function so what if I call this function we're worried about the implementation of that a little bit later but I'm going to go ahead and call that function and send the nums and notice in this case we passed it to that function and we said go ahead and user it quietly kind of passed it through now you see this could come from another library somewhere else and you could separately compile it it not be even here right and with illness I say numb start add and I'm going to put a 1.0 in this and if this was an old library hold the code the warning happens on that side and you're just calling into it but notice what happened when you call the function it gave us class cast exception a runtime exception in reality so you could argue that you could be no deal with that exception that warning but again the problem here is you're dealing with the old type or can you do about it Java does have one solution by the way you can go to the collections class and say collections dart checked type or checked class and then ask it to give you a particular implementation that would perform type checking for you and you can make that a little bit more smoother but still this is a problem we would have to deal with but again if you're listening to warnings properly maybe that's not too bad but there's another problem we have to deal with as well and this is about unboxing that happens quite a bit so in other words notice what's going to happen here imagine we have a function and I'm going to say get matching and get matching takes a type T and I'll kiss a this is going to be a matching instance and it's going to return to us some instance that is matching this so in this case P get matching T instance it's going to look for this instance and see if there is something that matches the style and return if it matches so in this case we could say check to see if instance matches with stuff right and if it matches this great what if it doesn't match us if not I'm going to say return null right so I'm going to turn a null to say I don't have what you're looking for sorry tough luck now the beauty of this is you can call this with different types but what's going to happen if I send an integer to this so for example let's say for a minute let's let's not do this for a second I'll return a one for now and I'm going to say in a you know matched value equals and I'm going to say get matching and send a one to this and then when I get back this I could say match to use and I can print this value out there is that is given to me right of course in this case what is T of course this would be a type integer that I'm passing to this right that's what I would expect to send in this case oh let's say I'm just sending the instance itself back how about that just to kind of get around it so that was good but on the other hand what if it is not present I'm going to turn a null in this case right now you say what's going to happen when I return I now notice you won't get a compilation ever in this code when you compile this code you will have absolutely no clue that this code is about to blow up but if you turn up the volume of the computer you will actually hear the Java compiler laughing right now saying these guys thought this was a good idea to use this generic type you right so the point really in this case is it returns an integer which happens to be a null in this case and as a result when you try to force the null into a into type you want to call it int value method under the covers and when you call Inc value on another type it's going to blow up with a null pointer exception and so as a result you can see in this case it results in a null pointer exception and the compiler wouldn't catch this for it and we get a runtime exception at this point so these are some of the consequences we have to be a bit careful about when it comes to using this the please my apologize I couldn't hear you say that again correct but it's compounded right because if I was receiving an integer time I could do a null check or I could use other kind of constructs for example I mean you could say don't return on knowledge to return an object or Union and then you can examine it but the point really is this is a really a more problem with auto unboxing than generics but the point that generics actually doesn't deal with integer pipe and you have to use into the uppercase integer type it's easy to fall into the trap so it is not a the genomics is not completely guilty here it has got other co-conspirators in this problem so it's not to be blamed alone for sure but but unfortunately it kind of leads you into it and then and then the other kind of get you so that's a problem um one other problem we have to deal with unfortunately is when you deal with the collection of objects you have to be a bit careful about this because I'll ever go into this example right now but I'll just mention this one of the problems you have to deal with this take a look at collection API and the list API collection API says I will remove an element which is an integer index the list API says I will remove an object which is given to me as a reference and when you go try this what you would happen is you are saying remove three and you're not sure if it takes three as an integer index or it auto boxes to me as an integer it removes the object really confusing and most of the time it's not what you expected and that's fun so play with it and see how that manifest itself and again those things can manifest very badly static fields are not really a good idea in these objects for example let's take a look at one example here now let's say for a minute that I want to create a type over here and and the type that I'm going to create here is going to be let's say a class called my list and I want to know how many elements of my list exist so I'm going to say private in a static int and let's call it as count our instance count and and I'm going to simply say my list is going to be the constructor and within the constructor I'm going to increment this count alright now I'm going to write the function will call it as int get camp and this is going to simply return the count back to us now we all know that it's not a good idea to access a static fee from an instance method I'm aware of it let's ignore that for a minute welcome back to it so now I'm going to say here my list of integers and I'm going to create a list 1 equals new my list of integer and I'm going to go ask him how many do you have so output list 1 dot count or rather get count and it should tell us how many objects we have it says we have one now I'm going to create one more of the same pie and I'll call this list two and of course you would argue it should really say I'll leave it on lists one by the way and it should really say - which is good right because those two are the same time and if you say that we have unlisted ooh but on the other hand I'm now going to go back here and say my list one more time and this is going to be off let's say double and I'm going to call it list three equals my list of double and and in this case I'm going to ask him list three d'art get count and I'm also going to ask list 1e how many elements it's got over here now of course if we really think about object and what these types are we mean I evilly think that there are two instances of my list integer and one instance of - double so we would probably say like when he should return - as a 1 and line 21 should return to us still left to right now when I run this code unfortunately you can see it says 3 + 3 right it's kind of like a buy one get one free offer where did that come from right well the reason why this messed up is these are really not separate types under the covers because a type erasure we only have a my list under the covers isn't it so notice what's going to happen at this time you say you know what make it that's really not fair because you would really not write this as a instance method you would do a static over here anyways to get to it isn't it so we could write this as a public static method over here and access that right now how do you get to this of course you could still get it through the object which is not a good idea so to avoid that you would say my list of integer dot and finally the compiler kind of tells you okay please don't do that I will admit to you this is all kind of a trick none of this exists so notice you cannot call that method because I mean it finally hit the guilt of that object the compiler right it said I can't fool you anymore I live with the truth to you so finally you say how do I really call this and you drop that and you call it like this and at that point it becomes very clear we're dealing with just one type under the covers and you start writing that you would simply say - start - start - start and it's very clear what type we are dealing on a similar note there's another problem we have to deal with as well and that problem is that when it comes to equality we don't have different types unfortunately so as a result if you take a list of integers and a list of double and you get the class from both of them and compare it they'll end up being equal assuming they're in the same container that's because they still are the same type under the colors and they are not really different type at this point so we got to be very careful now finally converting from generating non-generic something because be very careful I'll give you in the bar ten seconds what that and okrs suppose in this list I have let's say this is a non raw type we have and you have public void add object instance and then you also have let's say public void at all which is a collection of instances let's say instances right so this is a let's say this is a my list itself for example right so you've been asked to convert this from a genetic to a non-generic type you say cool I can do that and you put an angle T over here and then you say angle T here and then you say angle T here and you say why that was easy isn't it well one day you'll get a support for a call from the support and then they call you and say your code sucks and you would say I know my chord sucks but tell me how today right and you have to kind of question this and then you realize what they did was they create a collection of flute and they are trying to send a collection of banana in one case and the code doesn't accept it and then you realize darn it I shouldn't do this really and then you realize this should really be quashed in extending ste and that would be the correct implementation the mouth of the story is you cannot just substitute types with parameter type and go home right you have to right enough use examples use cases and try out your code and make sure your code actually works the way you like it to be just because the compiler compile your code it doesn't mean it's good but we all know that and yet we are so hopeful that someday that would be true that's all I have thank you
Info
Channel: Oracle Learning
Views: 39,127
Rating: 4.858521 out of 5
Keywords: java, javaone, 2012, generics, best, practices
Id: 34oiEq9nD0M
Channel Id: undefined
Length: 61min 47sec (3707 seconds)
Published: Fri Feb 01 2013
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.