23
More than you ever wanted to know about Java Generics Jeff Meister CMSC 420 Summer 2007

More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

Morethanyoueverwantedtoknowabout

JavaGenericsJeffMeister

CMSC420Summer2007

Page 2: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

GENERICS:AYOUNGLADY’SILLUSTRATEDPRIMERINFOURSLIDES

Theobligatoryreviewoftheboringstuff,or…

Page 3: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

Java1.4:LifeBeforeGenerics

Javacodeusedtolooklikethis:

ListlistOfFruits=newArrayList();listOfFruits.add(newFruit(“Apple”));Fruitapple=(Fruit)listOfFruits.remove(0);listOfFruits.add(newVegetable(“Carrot”));//Whoops!Fruitorange=(Fruit)listOfFruits.remove(0);//Run‐timeerror

Problem:Compilerdoesn’tknowlistOfFruits shouldonlycontainfruits

Page 4: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

ASillySoluMon

Wecouldmakeourownfruit‐onlylistclass:

classFruitList{voidadd(Fruitelement){…}Fruitremove(intindex){…}…}

Butwhataboutwhenwewantavegetable‐onlylistlater?Copy‐paste?Lotsofbloated,unmaintainablecode?

Page 5: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

Java1.5:NowWe’reTalking

Now,Javacodelookslikethis:

List<Fruit>listOfFruits=newArrayList<Fruit>();listOfFruits.add(newFruit(“Apple”));Fruitapple=listOfFruits.remove(0);listOfFruits.add(newVegetable(“Carrot”));//Compile‐timeerror

Hooray!CompilernowknowslistOfFruitscontainsonlyFruits

•  Soremove()mustreturnaFruit•  Andadd()cannottakeaVegetable

Page 6: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

Youguysrememberthis,right?

Here’showwe’dwritethatgenericListclass:

classList<T>{voidadd(Telement){…}Tremove(intindex){…}…}

Problemsolved!SimplyinvokeList<Fruit>,List<Vegetable>,andsoon.I’msureyou’vewri^encodelikethisbefore,solet’smoveto…

Page 7: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

THEFUNSTUFFHopeyouplannedonbeingconfusedtoday,becauseit’sMmefor…

Page 8: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

AbandonAllHope…

•  Genericsimplementparametricpolymorphism– Parametric:Thetypeparameter(e.g.,<T>)…– Polymorphism:…cantakemanyforms

•  However,ifwe’regoingtoprogramwithparameterizedtypes,weneedtounderstandhowthelanguagerulesapplytothem

•  Javagenericsareimplementedusingtypeerasure,whichleadstoallsortsofwackyissues,aswe’llsee

Page 9: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

Subtyping

SinceAppleisasubtypeofObject,isList<Apple>asubtypeofList<Object>?

List<Apple>apples=newArrayList<Apple>();List<Object>objs=apples;//Doesthiscompile?

Seemsharmless,butno!Ifthatworked,wecouldputOrangesinourList<Apple>likeso:

objs.add(newOrange());//OKbecauseobjsisaList<Object>Applea=apples.remove(0);//WouldassignOrangetoApple!

Page 10: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

AnAside:SubtypingandJavaArrays

•  Javaarraysactuallyhavethesubtypingproblemjustdescribed(theyarecovariant)

•  Thefollowingobviouslywrongcodecompiles,onlytofailatrun‐Mme:

Apple[]apples=newApple[3];Object[]objs=apples;//Thecompilerpermitsthis!objs[0]=newOrange();//ArrayStoreException

•  Avoidmixingarraysandgenerics(trustme)

Page 11: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

WildcardTypes

•  So,whatisList<Apple>asubtypeof?•  ThesupertypeofallkindsoflistsisList<?>,theListofunknown

•  The?isawildcardthatmatchesanything

•  Wecan’taddthings(exceptnull)toaList<?>,sincewedon’tknowwhattheListisreallyof

•  ButwecanretrievethingsandtreatthemasObjects,sinceweknowtheyareatleastthat

Page 12: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

BoundedWildcards

•  Wildcardtypescanhaveupperandlowerbounds

•  AList<?extendsFruit>isaListofitemsthathaveunknowntypebutareallatleastFruits– SoitcancontainFruitsandApplesbutnotPeas

•  AList<?superFruit>isaListofitemsthathaveunknowntypebutareallatmostFruits– SoitcancontainFruitsandObjectsbutnotApples

Page 13: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

BoundedWildcardsExampleclassWholesaleVendor<T>{voidbuy(inthowMany,List<?superT>fillMeUp){…}voidsell(List<?extendsT>emptyMe){…}…}

WholesaleVendor<Fruit>vendor=newWholesaleVendor<Fruit>();List<Food>stock=…;List<Apple>overstockApples=…;

//IcanbuyFoodfromtheFruitvendor:vendor.buy(100,stock);//IcansellmyApplestotheFruitvendor:vendor.sell(overstockApples);

Page 14: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

JoshBloch’sBoundedWildcardsRule

•  Use<?extendsT>whenparameterizedinstanceisaTproducer(forreading/input)

•  Use<?superT>whenparameterizedinstanceisaTconsumer(forwriMng/output)

Uhh…what?

Page 15: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

GenericMethods

•  Youcanparameterizemethodstoo.Here’sasignaturefromtheJavaAPI:

static<T>voidfill(List<?superT>list,Tobj);

•  Easyenough,yeah?Trythisoneonforsize:static<TextendsObject&Comparable<?superT>>T

max(Collection<?extendsT>coll);

•  Youdon’tneedtoexplicitlyinstanMategenericmethods(thecompilerwillfigureitout)

Page 16: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

HowGenericsareImplemented

•  RatherthanchangeeveryJVMbetweenJava1.4and1.5,theychosetouseerasure

•  Agerthecompilerdoesitstypechecking,itdiscardsthegenerics;theJVMneverseesthem!

•  Itworkssomethinglikethis:–  TypeinformaMonbetweenanglebracketsisthrownout,e.g.,List<String>List

– Usesoftypevariablesarereplacedbytheirupperbound(usuallyObject)

–  Castsareinsertedtopreservetype‐correctness

Page 17: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

ProsandConsofErasure

•  Good:BackwardcompaMbilityismaintained,soyoucansMlluselegacynon‐genericlibraries

•  Bad:Youcan’tfindoutwhattypeagenericclassisusingatrun‐Mme:

classExample<T>{voidmethod(Objectitem){if(iteminstanceofT){…}//Compilererror!TanotherItem=newT();//Compilererror!T[]itemArray=newT[10];//Compilererror!}}

Page 18: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

UsingLegacyCodeinGenericCode

•  SayIhavesomegenericcodedealingwithFruits,butIwanttocallthislegacylibraryfuncMon:

SmoothiemakeSmoothie(Stringname,Listfruits);

•  IcanpassinmygenericList<Fruit>forthefruitsparameter,whichhastherawtypeList.Butwhy?Thatseemsunsafe…makeSmoothie()couldsMckaVegetableinthelist,andthatwouldtastenasty!

Page 19: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

RawTypesandGenericTypes

•  Listdoesn’tmeanList<Object>,becausethenwecouldn’tpassinaList<Fruit>(subtyping,remember?)

•  Listdoesn’tmeanList<?>either,becausethenwecouldn’tassignaListtoaList<Fruit>(whichisalegaloperaMon)

•  Weneedbothofthesetoworkforgenericcodetointeroperatewithlegacycode

•  Rawtypesbasicallyworklikewildcardtypes,justnotcheckedasstringently–  TheseoperaMonsgenerateanuncheckedwarning

Page 20: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

TheProblemwithLegacyCode

•  “Callinglegacycodefromgenericcodeisinherentlydangerous;onceyoumixgenericcodewithnon‐genericlegacycode,allthesafetyguaranteesthatthegenerictypesystemusuallyprovidesarevoid.However,youaresMllbe^eroffthanyouwerewithoutusinggenericsatall.Atleastyouknowthecodeonyourendisconsistent.”–GiladBracha,JavaGenericsDeveloper

Page 21: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

MyAdviceonGenerics

•  Don’ttrytothinkaboutgenericcodeabstractly;makeanexampleinstanMaMoninyourheadandrunthroughscenariosusingit

•  Genericsareavaluabletooltoensuretypesafety,sousethem!Letthecompilerhelpyou

•  However,genericsalsocomplicatesyntax,andtheycangeneratesomenastyerrorsthatareapaintounderstandanddebug

Page 22: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

AnAnalogy:FuncMons

•  Problem:IwanttoperformthesamecomputaMononmanydifferentinputvalueswithoutwriMngthecomputaMonoverandover.

•  SoluMon:WriteafuncMon!Useavariabletorepresenttheinputvalue,andwriteyourcodetoperformthecomputaMononthisvariableinawaythatdoesnotdependonitsvalue.NowyoucancallthefuncMonmanyMmes,passingindifferentvaluesforthevariable.Easystuff.

Page 23: More than you ever wanted to know about Java Generics€¦ · Fruits – So it can contain Fruits and Apples but not Peas ... • You don’t need to explicitly instanate generic

GenericsProvideAnotherAbstracMon

•  Problem:Iwanttousethesameclass(ormethod)withobjectsofmanydifferenttypeswithoutwriMngtheclassoverandoverorsacrificingtypesafety.

•  SoluMon:Generifytheclass!UseavariableTtorepresenttheinputtype,andwriteyourcodetooperateonobjectsoftypeTinawaythatdoesnotdependontheactualvalueofT.NowyoucaninstanMatetheclassmanyMmes,passingindifferenttypesforT.

•  See?It’snotsobad.Genericsjustallowyoutoabstractovertypesinsteadofvalues.