




已阅读5页,还剩14页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
0外文原献JoshuaBloch,NealGafter著.JavaPuzzlers:Traps,Pitfalls,andCornerCases.JoshuaAddison-WesleyEducationalPublishersInc(2005-06)Puzzle1:OddityThefollowingmethodpurportstodeterminewhetheritssoleargumentisanoddnumber.Doesthemethodwork?publicstaticbooleanisOdd(inti)returni%2=1;Solution1:OddityAnoddnumbercanbedefinedasanintegerthatisdivisibleby2witharemainderof1.Theexpressioni%2computestheremainderwheniisdividedby2,soitwouldseemthatthisprogramoughttowork.Unfortunately,itdoesnt;itreturnsthewrongansweronequarterofthetimeWhyonequarter?Becausehalfofallintvaluesarenegative,andtheisOddmethodfailsforallnegativeoddvalues.Itreturnsfalsewheninvokedonanynegativevalue,whetherevenorodd.ThisisaconsequenceofthedefinitionofJavasremainderoperator(%).Itisdefinedtosatisfythefollowingidentityforallintvaluesaandallnonzerointvaluesb:(a/b)*b+(a%b)=aInotherwords,ifyoudivideabyb,multiplytheresultbyb,andaddtheremainder,youarebackwhereyoustartedJLS15.17.3.Thisidentitymakesperfectsense,butincombinationwithJavastruncatingintegerdivisionoperatorJLS15.17.2,itimpliesthatwhentheremainderoperationreturnsanonzeroresult,ithasthesamesignasitsleftoperand.TheisOddmethodandthedefinitionofthetermoddonwhichitwasbasedbothassumethatallremaindersarepositive.AlthoughthisassumptionmakessenseforsomekindsofdivisionBoxing,Javasremainderoperationisperfectlymatchedtoitsintegerdivisionoperation,whichdiscardsthefractionalpartofitsresult.Wheniisanegativeoddnumber,i%2isequalto-1ratherthan1,sotheisOddmethodincorrectlyreturnsfalse.Topreventthissortofsurprise,testthatyourmethodsbehave1properlywhenpassednegative,zero,andpositivevaluesforeachnumericalparameter.Theproblemiseasytofix.Simplycomparei%2to0ratherthanto1,andreversethesenseofthecomparison:publicstaticbooleanisOdd(inti)returni%2!=0;IfyouareusingtheisOddmethodinaperformance-criticalsetting,youwouldbebetteroffusingthebitwiseANDoperator(&)inplaceoftheremainderoperator:publicstaticbooleanisOdd(inti)return(iThesecondversionmayrunmuchfasterthanthefirst,dependingonwhatplatformandvirtualmachineyouareusing,andisunlikelytorunslower.Asageneralrule,thedivideandremainderoperationsareslowcomparedtootherarithmeticandlogicaloperations.Itsabadideatooptimizeprematurely,butinthiscase,thefasterversionisasclearastheoriginal,sothereisnoreasontoprefertheoriginal.Insummary,thinkaboutthesignsoftheoperandsandoftheresultwheneveryouusetheremainderoperator.Thebehaviorofthisoperatorisobviouswhenitsoperandsarenonnegative,butitisntsoobviouswhenoneorbothoperandsarenegative.Puzzle2:TimeforaChangeConsiderthefollowingwordproblem:Tomgoestotheautopartsstoretobuyasparkplugthatcosts$1.10,butallhehasinhiswalletaretwo-dollarbills.Howmuchchangeshouldhegetifhepaysforthesparkplugwithatwo-dollarbill?Hereisaprogramthatattemptstosolvethewordproblem.Whatdoesitprint?publicclassChangepublicstaticvoidmain(Stringargs)System.out.println(2.00-1.10);2Solution2:TimeforaChangeNaively,youmightexpecttheprogramtoprint0.90,buthowcoulditknowthatyouwantedtwodigitsafterthedecimalpoint?Ifyouknowsomethingabouttherulesforconvertingdoublevaluestostrings,whicharespecifiedbythedocumentationforDouble.toStringJava-API,youknowthattheprogramprintstheshortestdecimalfractionsufficienttodistinguishthedoublevaluefromitsnearestneighbor,withatleastonedigitbeforeandafterthedecimalpoint.Itseemsreasonable,then,thattheprogramshouldprint0.9.Reasonable,perhaps,butnotcorrect.Ifyourantheprogram,youfoundthatitprints0.8999999999999999.Theproblemisthatthenumber1.1cantberepresentedexactlyasadouble,soitisrepresentedbytheclosestdoublevalue.Theprogramsubtractsthisvaluefrom2.Unfortunately,theresultofthiscalculationisnottheclosestdoublevalueto0.9.Theshortestrepresentationoftheresultingdoublevalueisthehideousnumberthatyouseeprinted.Moregenerally,theproblemisthatnotalldecimalscanberepresentedexactlyusingbinaryfloating-point.Ifyouareusingrelease5.0oralaterrelease,youmightbetemptedtofixtheprogrambyusingtheprintffacilitytosettheprecisionoftheoutput:/Poorsolution-stillusesbinaryfloating-point!System.out.printf(%.2f%n,2.00-1.10);Thisprintstherightanswerbutdoesnotrepresentageneralsolutiontotheunderlyingproblem:Itstillusesdoublearithmetic,whichisbinaryfloating-point.Floating-pointarithmeticprovidesgoodapproximationsoverawiderangeofvaluesbutdoesnotgenerallyyieldexactresults.Binaryfloating-pointisparticularlyill-suitedtomonetarycalculations,asitisimpossibletorepresent0.1oranyothernegativepowerof10exactlyasafinite-lengthbinaryfractionEJItem31.Onewaytosolvetheproblemistouseanintegraltype,suchasintorlong,andtoperformthecomputationincents.Ifyougothisroute,makesuretheintegraltypeislargeenoughtorepresentallthevaluesyouwilluseinyourprogram.Forthispuzzle,intisample.Hereishowtheprintlnlooksifwerewriteitusingintvaluestorepresentmonetaryvaluesincents.Thisversionprints90cents,whichistherightanswer:3System.out.println(200-110)+cents);AnotherwaytosolvetheproblemistouseBigDecimal,whichperformsexactdecimalarithmetic.ItalsointeroperateswiththeSQLDECIMALtypeviaJDBC.Thereisonecaveat:AlwaysusetheBigDecimal(String)constructor,neverBigDecimal(double).Thelatterconstructorcreatesaninstancewiththeexactvalueofitsargument:newBigDecimal(.1)returnBigDecimarepresenting0.1000000000000000055511151231257827021181583404541015625.UsingBigDecimalcorrectly,theprogramprintstheexpectedresultof0.90:importjava.math.BigDecimal;publicclassChangepublicstaticvoidmain(Stringargs)System.out.println(newBigDecimal(2.00).subtract(newBigDecimal(1.10);Thisversionisnotterriblypretty,asJavaprovidesnolinguisticsupportforBigDecimal.CalculationswithBigDecimalarealsolikelytobeslowerthanthosewithanyprimitivetype,whichmightbeanissueforsomeprogramsthatmakeheavyuseofdecimalcalculations.Itisofnoconsequenceformostprograms.Insummary,avoidfloatanddoublewhereexactanswersarerequired;formonetarycalculations,useint,long,orBigDecimal.Forlanguagedesigners,considerprovidinglinguisticsupportfordecimalarithmetic.Oneapproachistoofferlimitedsupportforoperatoroverloading,sothatarithmeticoperatorscanbemadetoworkwithnumericalreferencetypes,suchasBigDecimal.Anotherapproachistoprovideaprimitivedecimaltype,asdidCOBOLandPL/I.Puzzle3:LongDivisionThispuzzleiscalledLongDivisionbecauseitconcernsaprogramthatdividestwolongvalues.Thedividendrepresentsthenumberofmicrosecondsinaday;thedivisor,thenumberofmillisecondsinaday.Whatdoestheprogramprint?publicclassLongDivision4publicstaticvoidmain(Stringargs)finallongMICROS_PER_DAY=24*60*60*1000*1000;finallongMILLIS_PER_DAY=24*60*60*1000;System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY);Solution3:LongDivisionThispuzzleseemsreasonablystraightforward.Thenumberofmillisecondsperdayandthenumberofmicrosecondsperdayareconstants.Forclarity,theyareexpressedasproducts.Thenumberofmicrosecondsperdayis(24hours/day60minutes/hour60seconds/minute1,000milliseconds/second1,000microseconds/millisecond).Thenumberofmillisecondsperdaydiffersonlyinthatitismissingthefinalfactorof1,000.Whenyoudividethenumberofmicrosecondsperdaybythenumberofmillisecondsperday,allthefactorsinthedivisorcancelout,andyouareleftwith1,000,whichisthenumberofmicrosecondspermillisecond.Boththedivisorandthedividendareoftypelong,whichiseasilylargeenoughtoholdeitherproductwithoutoverflow.Itseems,then,thattheprogrammustprint1000.Unfortunately,itprints5.Whatexactlyisgoingonhere?TheproblemisthatthecomputationoftheconstantMICROS_PER_DAYdoesoverflow.Althoughtheresultofthecomputationfitsinalongwithroomtospare,itdoesntfitinanint.Thecomputationisperformedentirelyinintarithmetic,andonlyafterthecomputationcompletesistheresultpromotedtoalong.Bythen,itstoolate:Thecomputationhasalreadyoverflowed,returningavaluethatistoolowbyafactorof200.ThepromotionfrominttolongisawideningprimitiveconversionJLS5.1.2,whichpreservesthe(incorrect)numericalvalue.ThisvalueisthendividedbyMILLIS_PER_DAY,whichwascomputedcorrectlybecauseitdoesfitinanint.Theresultofthisdivisionis5.Sowhyisthecomputationperformedinintarithmetic?Becauseallthefactorsthataremultipliedtogetherareintvalues.Whenyoumultiplytwointvalues,yougetanotherintvalue.Javadoesnothavetargettyping,alanguagefeaturewhereinthetypeofthevariablein5whicharesultistobestoredinfluencesthetypeofthecomputation.Itseasytofixtheprogrambyusingalongliteralinplaceofanintasthefirstfactorineachproduct.Thisforcesallsubsequentcomputationsintheexpressiontobedonewithlongarithmetic.AlthoughitisnecessarytodothisonlyintheexpressionforMICROS_PER_DAY,itisgoodformtodoitinbothproducts.Similarly,itisntalwaysnecessarytousealongasthefirstvalueinaproduct,butitisgoodformtodoso.Beginningbothcomputationswithlongvaluesmakesitclearthattheywontoverflow.Thisprogramprints1000asexpected:publicclassLongDivisionpublicstaticvoidmain(Stringargs)finallongMICROS_PER_DAY=24L*60*60*1000*1000;finallongMILLIS_PER_DAY=24L*60*60*1000;System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY);Thelessonissimple:Whenworkingwithlargenumbers,watchoutforoverflowitsasilentkiller.Justbecauseavariableislargeenoughtoholdaresultdoesntmeanthatthecomputationleadingtotheresultisofthecorrecttype.Whenindoubt,performtheentirecomputationusinglongarithmetic.Thelessonforlanguagedesignersisthatitmaybeworthreducingthelikelihoodofsilentoverflow.Thiscouldbedonebyprovidingsupportforarithmeticthatdoesnotoverflowsilently.Programscouldthrowanexceptioninsteadofoverflowing,asdoesAda,ortheycouldswitchtoalargerinternalrepresentationautomaticallyasrequiredtoavoidoverflow,asdoesLisp.Bothoftheseapproachesmayhaveperformancepenaltiesassociatedwiththem.Anotherwaytoreducethelikelihoodofsilentoverflowistosupporttargettyping,butthisaddssignificantcomplexitytothetypesystemModula-31.4.8.Puzzle4:ItsElementaryOK,sothelastpuzzlewasabittricky,butitwasaboutdivision.Everyoneknowsthatdivisionistough.Thisprograminvolvesonlyaddition.Whatdoesitprint?6publicclassElementarypublicstaticvoidmain(Stringargs)System.out.println(12345+5432l);Solution4:ItsElementaryOnthefaceofit,thislookslikeaneasypuzzlesoeasythatyoucansolveitwithoutpencilorpaper.Thedigitsoftheleftoperandoftheplusoperatorascendfrom1to5,andthedigitsoftherightoperanddescend.Therefore,thesumsofcorrespondingdigitsremainconstant,andtheprogrammustsurelyprint66666.Thereisonlyoneproblemwiththisanalysis:Whenyouruntheprogram,itprints17777.CoulditbethatJavahasanaversiontoprintingsuchabeastlynumber?Somehowthisdoesntseemlikeaplausibleexplanation.Thingsareseldomwhattheyseem.Takethisprogram,forinstance.Itdoesntsaywhatyouthinkitdoes.Takeacarefullookatthetwooperandsofthe+operator.Weareaddingtheintvalue12345tothelongvalue5432l.Notethesubtledifferenceinshapebetweenthedigit1atthebeginningoftheleftoperandandthelowercaseletterelattheendoftherightoperand.Thedigit1hasanacuteanglebetweenthehorizontalstroke,orarm,andtheverticalstroke,orstem.Thelowercaseletterel,bycontrast,hasarightanglebetweenthearmandthestem.Beforeyoucryfoul,notethatthisissuehascausedrealconfusion.Alsonotethatthepuzzlestitlecontainedahint:ItsEl-ementary;getit?Finally,notethatthereisareallessonhere.Alwaysuseacapitalel(L)inlongliterals,neveralowercaseel(l).Thiscompletelyeliminatesthesourceofconfusiononwhichthepuzzlerelies:System.out.println(12345+5432L);Similarly,avoidusingaloneel(l)asavariablename.Itisdifficulttotellbylookingatthiscodesnippetwhetheritprintsthelistlorthenumber1:/Badcode-usesel(l)asavariablenameListl=newArrayList();l.add(Foo);System.out.println(1);7Insummary,thelowercaseletterelandthedigit1arenearlyidenticalinmosttypewriterfonts.Toavoidconfusingthereadersofyourprogram,neverusealowercaseeltoterminatealongliteralorasavariablename.JavainheritedmuchfromtheCprogramminglanguage,includingitssyntaxforlongliterals.Itwasprobablyamistaketoallowlongliteralstobewrittenwithalowercaseel.Puzzle5:TheJoyofHexThefollowingprogramaddstwohexadecimal,orhex,literalsandprintstheresultinhex.Whatdoestheprogramprint?publicclassJoyOfHexpublicstaticvoidmain(Stringargs)System.out.println(Long.toHexString(0x100000000L+0xcafebabe);Solution5:TheJoyofHexItseemsobviousthattheprogramshouldprint1cafebabe.Afterall,thatisthesumofthehexnumbers10000000016andcafebabe16.Theprogramuseslongarithmetic,whichpermits16hexdigits,soarithmeticoverflowisnotanissue.Yet,ifyourantheprogram,youfoundthatitprintscafebabe,withnoleading1digit.Thisoutputrepresentsthelow-order32bitsofthecorrectsum,butsomehowthethirty-thirdbitgetslost.Itisasiftheprogramweredoingintarithmeticinsteadoflong,orforgettingtoaddthefirstoperand.Whatsgoingonhere?Decimalliteralshaveanicepropertythatisnotsharedbyhexadecimaloroctalliterals:DecimalliteralsareallpositiveJLS3.10.1.Towriteanegativedecimalconstant,youusetheunarynegationoperator(-)incombinationwithadecimalliteral.Inthisway,youcanwriteanyintorlongvalue,whetherpositiveornegative,indecimalform,andnegativedecimalconstantsareclearlyidentifiablebythepresenceofaminussign.Notsoforhexadecimalandoctalliterals.Theycantakeonbothpositiveandnegativevalues.Hexandoctalliteralsarenegativeiftheirhigh-orderbitisset.Inthisprogram,thenumber80xcafebabeisanintconstantwithitshigh-orderbitset,soitisnegative.Itisequivalenttothedecimalvalue-889275714.Theadditionperformedbytheprogramisamixed-typecomputation:Theleftoperandisoftypelong,andtherightoperandisoftypeint.Toperformthecomputation,JavapromotestheintvaluetoalongwithawideningprimitiveconversionJLS5.1.2andaddsthetwolongvalues.Becauseintisasignedintegraltype,theconversionperformssignextension:Itpromotesthenegativeintvaluetoanumericallyequallongvalue.Therightoperandoftheaddition,0xcafebabe,ispromotedtothelongvalue0xffffffffcafebabeL.Thisvalueisthenaddedtotheleftoperand,whichis0x100000000L.Whenviewedasanint,thehigh-order32bitsofthesign-extendedrightoperandare-1,andthehigh-order32bitsoftheleftoperandare1.Addthesetwovaluestogetherandyouget0,whichexplainstheabsenceoftheleading1digitintheprogramsoutput.Hereishowtheadditionlookswhendoneinlonghand.(Thedigitsatthetopoftheadditionarecarries.)11111110xffffffffcafebabeL+0x0000000100000000L0x00000000cafebabeLFixingtheproblemisassimpleasusingalonghexliteraltorepresenttherightoperand.Thisavoidsthedamagingsignextension,andtheprogramprintstheexpectedresultof1cafebabe:publicclassJoyOfHexpublicstaticvoidmain(Stringargs)System.out.println(Long.toHexString(0x100000000L+0xcafebabeL);Thelessonofthispuzzleisthatmixed-typecomputationscanbeconfusing,moresogiventhathexandoctalliteralscantakeonnegativevalueswithoutanexplicitminussign.Toavoidthissortofdifficulty,itisgenerallybesttoavoidmixed-typecomputations.For9languagedesigners,itisworthconsideringsupportforunsignedintegraltypes,whicheliminatethepossibilityofsignextension.Onemightarguethatnegativehexandoctalliteralsshouldbeprohibited,butthiswouldlikelyfrustrateprogrammers,whooftenusehexliteralstorepresentvalueswhosesignisofnosignificance.Puzzle6:MulticastCastsareusedtoconvertavaluefromonetypetoanother.Thisprogramusesthreecastsinsuccession.Whatdoesitprint?publicclassMulticastpublicstaticvoidmain(Stringargs)System.out.println(int)(char)(byte)-1);Solution6:MulticastThisprogramisconfusinganywayyousliceit.Itstartswiththeintvalue-1,thencaststheinttoabyte,thentoachar,andfinallybacktoanint.Thefirstcastnarrowsthevaluefrom32bitsdownto8,thesecondwidensitfrom8bitsto16,andthefinalcastwidensitfrom16bitsbackto32.Doesthevalueendupbackwhereitstarted?Ifyourantheprogram,youfoundthatitdoesnot.Itprints65535,butwhy?Theprogramsbehaviordependscriticallyonthesignextensionbehaviorofcasts.Javausestwos-complementbinaryarithmetic,sotheintvalue-1hasall32bitsset.Thecastfrominttobyteisstraightforward.ItperformsanarrowingprimitiveconversionJLS5.1.3,whichsimplylopsoffallbutthelow-order8bits.Thisleavesabytevaluewithall8bitsset,which(still)represents1.Thecastfrombytetocharistrickierbecausebyteisasignedtypeandcharunsigned.Itisusuallypossibletoconvertfromoneintegraltypetoawideronewhilepreservingnumericalvalue,butitisimpossibletorepresentanegativebytevalueasachar.Therefore,theconversionfrombytetocharisnotconsideredawideningprimitiveconversionJLS5.1.2,butawideningandnarrowingprimitiveconversionJLS5.1.4:Thebyteisconvertedtoanintandtheinttoachar.Allofthismaysoundabitcomplicated.Luckily,thereisasimplerulethatdescribesthesignextensionbehaviorwhenconverting10fromnarrowerintegraltypestowider:Signextensionisperformedifthetypeoftheoriginalvalueissigned;zeroextensionifitisachar,regardlessofthetypetowhichitisbeingconverted.Knowingthisrulemakesiteasytosolvethepuzzle.Becausebyteisasignedtype,signextensionoccurswhenconvertingthebytevalue1toachar.Theresultingcharvaluehasall16bitsset,soitisequalto2161,or65,535.Thecastfromchartointisalsoawideningprimitiveconversion,sotheruletellsusthatzeroextensionisperformedratherthansignextension.Theresultingintvalueis65535,whichisjustwhattheprogramprints.Althoughthereisasimpleruledescribingthesignextensionbehaviorofwideningprimitiveconversionsbetweensignedandunsignedintegraltypes,itisbestnottowriteprogramsthatdependonit.Ifyouaredoingawideningconversiontoorfromachar,whichistheonlyunsignedintegraltype,itisbesttomakeyourintentionsexplicit.Ifyouareconvertingfromacharvaluectoawidertypeandyoudontwantsignextension,considerusingabitmaskforclarity,eventhoughitisntrequired:inti=cAlternatively,writeacommentdescribingthebehavioroftheconversion:inti=c;/SignextensionisnotperformedIfyouareconvertingfromacharvaluectoawiderintegraltypeandyouwantsignextension,castthechartoashort,whichisthesamewidthasacharbutsigned.Giventhesubtletyofthiscode,youshouldalsowriteacomment:inti=(short)c;/CastcausessignextensionIfyouareconvertingfromabytevaluebtoacharandyoudontwantsignextension,youmustuseabitmasktosuppressit.Thisisacommonidiom,sonocommentisnecessary:charc=(char)(bIfyouareconvertingfromabytetoacharandyouwantsignextension,writeacomment:charc=(char)b;/SignextensionisperformedThelessonissimple:Ifyoucanttellwhataprogramdoesbylookingatit,itprobablydoesntdowhatyouwant.Striveforclarity.Althoughasimpleruledescribesthesignextensionbehaviorofwideningconversionsinvolvingsignedandunsignedintegraltypes,mostprogrammersdontknowit.11Ifyourprogramdependsonit,makeyourintentionscler12中文翻译Java谜题1表达式谜题谜题1:奇数性下面的方法意图确定它那唯一的参数是否是一个奇数。这个方法
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 产品品质测试记录模版提供规范的操作指南
- 2025-2030中医诊所连锁化经营与品牌标准化建设研究报告
- 转载好美的一首诗7篇
- 2025至2030高尔夫练习场行业市场深度研究及发展前景投资可行性分析报告
- 媒体版权贸易合同书
- 消费者决策影响-洞察及研究
- 未来的笔作文500字(14篇)
- 学校设施设备采购与维护合同协议
- 园区物业服务管理合同
- 2025年湖北省省直机关公开遴选公务员笔试题及答案解析(A类)
- 2025年检验检测机构资质认定(授权签字人)试题(含答案)
- 建筑质量安全知识培训课件
- 抑郁症治疗个案分析文献综述
- 面试必杀技:保研面试实战模拟题库解析
- 2025-2026粤教粤科版(2024)科学三年级上册教学设计(附目录)
- 2025年金融机具行业研究报告及未来发展趋势预测
- 2025年安徽干部教育在线必修课考试试题及答案
- 2025年度中级经济师职称评审聘用合同样本
- 新业务开发管理办法
- 民事起诉状要素式(买卖合同纠纷)
- 超声新技术新项目应用与发展
评论
0/150
提交评论