Programmēšana

Izmantojiet == (vai! =), Lai salīdzinātu Java Enums

Lielākā daļa jauno Java izstrādātāju ātri uzzina, ka Java virknes parasti jāsalīdzina, izmantojot String.equals (Object), nevis izmantojot ==. Tas tiek atkārtoti uzsvērts un pastiprināts jaunajiem izstrādātājiem, jo ​​viņi to dara gandrīz vienmēr nozīmē salīdzināt virknes saturu (faktiskās virknes veidojošās rakstzīmes), nevis virknes identitāti (tās adresi atmiņā). Es uzskatu, ka mums vajadzētu nostiprināt priekšstatu par to == var izmantot Enum.equals (Object) vietā. Es pamatoju šo apgalvojumu šī ziņojuma atlikušajā daļā.

Es uzskatu, ka ir četri iemesli == salīdzināt Java enums ir gandrīz vienmēr vēlams izmantot metodi "vienāds":

  1. The == par enums nodrošina tādu pašu paredzamo salīdzinājumu (saturu) kā ir vienāds
  2. The == par enums ir neapšaubāmi vieglāk lasāms (mazāk runīgs) nekā ir vienāds
  3. The == enums ir vairāk nekaitīgs nekā ir vienāds
  4. The == on enums nodrošina kompilēšanas laika (statisko) pārbaudi, nevis izpildlaika pārbaudi

Otrs iepriekš uzskaitītais iemesls ("neapšaubāmi vairāk lasāms") acīmredzami ir viedokļa jautājums, taču par to, ka par mazāk izteiksmīgu daļu, var vienoties. Pirmais iemesls, kāpēc es parasti dodu priekšroku == salīdzinot uzskaitījumus, ir sekas tam, kā Java valodas specifikācija apraksta uzskaitījumus. 8.9. Sadaļā ("Enums") teikts:

Mēģinājums skaidri uzrādīt uzskaites tipu ir sastādīšanas laika kļūda. Galīgā klona metode programmā Enum nodrošina, ka enuma konstantes nekad nevar klonēt, un īpašā apstrāde, izmantojot seriālizācijas mehānismu, nodrošina, ka deserializācijas rezultātā nekad netiek izveidoti dublikātu gadījumi. Enum tipu atstarojošs eksponēšana ir aizliegta. Šīs četras lietas kopā nodrošina to, ka nav neviena enum veida gadījuma, izņemot tos, kurus nosaka enum konstantes.

Tā kā katrai enuma konstantei ir tikai viens gadījums, ir atļauts izmantot == metodi equals metodes vietā, salīdzinot divas objekta atsauces, ja ir zināms, ka vismaz viena no tām attiecas uz enum konstanti. (Vienāda ar metodi Enum ir galīga metode, kas tikai izsauc argumentā super.equals un atgriež rezultātu, tādējādi veicot identitātes salīdzināšanu.)

Izraksts no iepriekš parādītās specifikācijas nozīmē un pēc tam skaidri norāda, ka to ir droši lietot == operatoram, lai salīdzinātu divus uzskaitījumus, jo nav tā, ka vienas un tās pašas uzskaites konstantes var būt vairāk nekā viens gadījums.

Ceturtā priekšrocība == beidzies .vienlīdzīgi ja salīdzina skaitļus, tas ir saistīts ar apkopošanas laika drošību. Pielietojums == piespiež stingrāku kompilēšanas laika pārbaudi nekā .vienlīdzīgi jo Object.equals (Object) pēc līguma jāņem patvaļīga Objekts. Izmantojot statiski ierakstītu valodu, piemēram, Java, es ticu, cik vien iespējams, izmantojot šīs statiskās rakstīšanas priekšrocības. Pretējā gadījumā es izmantotu dinamiski drukātu valodu. Es uzskatu, ka viena no efektīvās Java atkārtotajām tēmām ir tieši tāda: dodiet priekšroku statiskā tipa pārbaudei, kad vien iespējams.

Piemēram, pieņemsim, ka man bija parasts enums, ko sauca Augļi un es mēģināju to salīdzināt ar klases java.awt.Color. Izmantojot == operators ļauj man iegūt problēmas sastādīšanas laika kļūdu (ieskaitot iepriekšēju paziņojumu manā iecienītajā Java IDE). Šeit ir kodu saraksts, kas mēģina salīdzināt pielāgoto enum ar JDK klasi, izmantojot == operators:

/ ** * Norādiet, ja norādīts. Krāsa ir arbūzs. * * Šīs metodes ieviešana tiek komentēta, lai izvairītos no sastādītāja kļūdas *, kas likumīgi neļauj == salīdzināt divus objektus, kas nav un * nekad nevar būt viens un tas pats. * * @param kandidāts Krāsa Krāsa, kas nekad nebūs arbūzs. * @return Nekad nevajadzētu būt patiesai. * / public boolean isColorWatermelon (java.awt.Color kandidāta krāsa) {// Šis augļu un krāsu salīdzinājums novedīs pie sastādītāja kļūdas: // kļūda: nesalīdzināmi veidi: augļi un krāsas atgriež augļus. ŪDENSMENIS == kandidāta krāsa } 

Sastādītāja kļūda tiek parādīta nākošajā ekrāna momentuzņēmumā.

Lai gan es neesmu kļūdu cienītājs, es gribētu, lai kompilēšanas laikā tās tiktu notvertas statiski, nevis atkarībā no izpildlaika pārklājuma. Vai es būtu izmantojis ir vienāds metodi šim salīdzinājumam kods būtu sastādījis labi, bet metode vienmēr atgrieztos nepatiesa nepatiesa, jo nav nekāda veida a putekļi. piemēri. Augļi enum būs vienāds ar a java.awt.Color klasē. Es to neiesaku, bet šeit ir salīdzināšanas metode, izmantojot .vienlīdzīgi:

/ ** * Norādiet, vai norādītā krāsa ir avene. Tas ir pilnīgs absurds *, jo krāsa nekad nevar būt vienāda ar augli, taču sastādītājs atļauj šo * pārbaudi, un tikai izpildlaika noteikšana var norādīt, ka tie nav * vienādi, kaut arī nekad nevar būt vienādi. Tā NEDRĪKST rīkoties. * * @param kandidāts Krāsu krāsa, kas nekad nebūs avene. * @return {@code false}. Vienmēr. * / public boolean isColorRaspberry (java.awt.Color kandidātsColor) {// // NEDARI ŠO: Pūles un maldinoša koda izšķiešana !!!!!!!! // atgriešanās Augļi. AVENES. vienādas (kandidāta krāsa); } 

"Jaukā" lieta, kas saistīta ar iepriekš minēto, ir kompilēšanas laika kļūdu trūkums. Tas apkopo skaisti. Diemžēl tas tiek apmaksāts ar potenciāli augstu cenu.

Pēdējā priekšrocība, kuru es uzskaitīju, izmantojot == nevis Enum.vienāds salīdzinot uzskaiti, ir izvairīšanās no baidītā NullPointerException. Kā es norādīju efektīvā Java NullPointerException apstrādē, man parasti patīk izvairīties no negaidīta NullPointerExceptions. Pastāv ierobežots situāciju kopums, kurā es patiešām vēlos, lai nulles esamība tiktu uzskatīta par izņēmuma gadījumu, taču bieži es dodu priekšroku graciozākai ziņošanai par problēmu. Priekšrocība, salīdzinot uzskaitījumus ar == ir tāds, ka nulli var salīdzināt ar nulles skaitli, nesaskaroties ar NullPointerException (NPE). Šī salīdzinājuma rezultāts acīmredzami ir nepatiesa.

Viens veids, kā izvairīties no NPE, lietojot .equals (objekts) ir izsaukt ir vienāds metodi pret enum konstanti vai zināmu nulles enum un pēc tam nodod apšaubāmā rakstura potenciālo uzskaiti (iespējams, nulle) kā parametru ir vienāds metodi. Tas bieži tiek darīts vairākus gadus Java ar Strings, lai izvairītos no NPE. Tomēr ar == operators, salīdzināšanas kārtībai nav nozīmes. Man tas patīk.

Esmu izteicis savus argumentus, un tagad es pārietu uz dažiem kodu piemēriem. Nākamais saraksts ir iepriekš minētā hipotētiskā augļu uzskaitījuma realizācija.

Augļi.java

iepakojums dustin.piemēri; sabiedrības enum Augļi {ĀBOLI, BANĀNA, MELNES, MELENES, ĶIRŠI, VĪNOGAS, KIWI, MANGO, APELSINI, AVENES, ZEMENES, TOMATO, ARĪZELI 

Nākamais kodu saraksts ir vienkārša Java klase, kas nodrošina metodes, kā noteikt, vai konkrētais enums vai objekts ir noteikts auglis. Es parasti šādus čekus ievietotu pašā uzskaitē, taču šeit tie manā ilustratīviem un demonstrējošiem nolūkiem darbojas labāk atsevišķā klasē. Šajā klasē ir iekļautas divas iepriekš salīdzināšanas metodes Augļi uz Krāsa ar abiem == un ir vienāds. Protams, metode, izmantojot == lai salīdzinātu ierakstu ar klasi, šī daļa bija jāizsaka komentārā, lai pareizi sastādītu.

EnumComparisonMain.java

iepakojums dustin.piemēri; public class EnumComparisonMain {/ ** * Norādiet, vai piegādātie augļi ir arbūzs ({@code true} vai nē * ({@code false}). * * @param kandidātsFruit Augļi, kas var būt arbūzs vai nav; null ir * pilnīgi pieņemams (nēsājiet to!). * @return {@code true}, ja augļi ir arbūzs; {@code false} ja * ar nosacījumu, ka augļi NAV arbūzs. * / public boolean isFruitWatermelon (Fruit pretendentFruit) {return kandidātsFruit = = Fruit.WATERMELON;} / ** * Norādiet, vai sniegtais objekts ir Fruit.WATERMELON ({@code true}) vai * nav ({@code false}). * * @Param kandidātsObject Objekts, kas var būt vai nevar būt arbūzs un, iespējams, pat nav auglis! * @return {@code true}, ja norādītais objekts ir auglis. ARBŪZIS; * {@code false} ja sniegtais objekts nav Fruit.WATERMELON. * / public boolean isObjectWatermelon (Object kandidātsObject ) {atgriešanās kandidātsObjekts == Augļi. ARBŪZIS;} / ** * Norādiet, ja norādīts, krāsa ir arbūzs. * * Šīs metodes ieviešana ir komentēta izvairieties no sastādītāja kļūdas *, kas likumīgi neļauj == salīdzināt divus objektus, kas nav un * nekad nevar būt viens un tas pats. * * @param kandidāts Krāsa Krāsa, kas nekad nebūs arbūzs. * @return Nekad nevajadzētu būt patiesai. * / public boolean isColorWatermelon (java.awt.Color kandidātkrāsa) {// Lai izvairītos no sastādītāja kļūdas, vajadzēja komentēt augļu un krāsu salīdzinājumu: // kļūda: nesalīdzināmi veidi: augļu un krāsu atgriešana /*Fruit.WATERMELON == kandidāta krāsa * / nepatiesa; } / ** * Norādiet, vai sniegtie augļi ir zemenes ({@code true}) vai nē * ({@code false}). * * @param kandidātsAugļu augļi, kas var būt vai var nebūt zemenes; null ir * pilnīgi pieņemams (uzvelciet to!). * @return {@code true}, ja augļi ir zemenes; {@code false} ja * sniegtie augļi NAV zemenes. * / public boolean isFruitStrawberry (augļu kandidātsFruit) {return Fruit.STRAWBERRY == kandidātsFruit; } / ** * Norādiet, vai sniegtie augļi ir aveņu ({@code true}) vai nē * ({@code false}). * * @param kandidātsAugļu augļi, kas var būt vai var nebūt aveņu; null ir * pilnīgi un pilnīgi nepieņemami; lūdzu, neizturiet nulli, lūdzu, * lūdzu, lūdzu. * @return {@code true}, ja augļi ir aveņu; {@code false} ja * ar nosacījumu, ka augļi NAV avenes. * / public boolean isFruitRaspberry (Augļu kandidātsAugļi) {atgriešanās kandidātsFruit.equals (Augļi.APSNES); } / ** * Norādiet, vai norādītais objekts ir auglis. AVENES ({@code true}) vai * nav ({@code false}). * * @param kandidātsObjekts Objekts, kas var būt vai var nebūt Avene un var būt * vai pat nebūt auglis! * @return {@code true}, ja ir norādīts, ka objekts ir auglis. AVENES; {@code false} *, ja tas nav auglis vai avene. * / public boolean isObjectRaspberry (Object kandidātsObject) {atgriezt kandidātuObject.equals (Augļi.APSNES); } / ** * Norādiet, vai norādītā krāsa ir avene. Tas ir pilnīgs absurds *, jo krāsa nekad nevar būt vienāda ar augli, taču sastādītājs atļauj šo * pārbaudi, un tikai izpildlaika noteikšana var norādīt, ka tie nav * vienādi, kaut arī nekad nevar būt vienādi. Tas ir, kā NEDARĪT rīkoties. * * @param kandidāts Krāsu krāsa, kas nekad nebūs avene. * @return {@code false}. Vienmēr. * / public boolean isColorRaspberry (java.awt.Color kandidātsColor) {// // NEDARI ŠO: Pūles un maldinoša koda izšķiešana !!!!!!!! // atgriešanās Augļi. AVENES. vienādas (kandidāta krāsa); } / ** * Norādiet, vai sniegtie augļi ir vīnogas ({@code true}) vai nē * ({@code false}). * * @param kandidātsAugļu augļi, kas var būt vai nebūt vīnogas; null ir * pilnīgi pieņemams (uzvelciet to!). * @return {@code true}, ja augļi ir vīnogas; {@code false} ja * ar nosacījumu, ka augļi NAV vīnogu. * / public boolean isFruitGrape (augļu kandidātsFruit) {return Fruit.GRAPE.equals (kandidātsFruit); }} 

Es nolēmu tuvoties iepriekšminētajās metodēs ietverto ideju demonstrēšanai, izmantojot vienības testus. Jo īpaši es izmantoju Groovy's GroovyTestCase. Šī klase Groovy darbināmu vienību testēšanas izmantošanai ir nākamajā kodu sarakstā.

EnumComparisonTest.groovy

$config[zx-auto] not found$config[zx-overlay] not found