Is het oké om NullPointerException programmatisch te gooien?

Als er een post-conditie is, mag die retourwaarde van een methode niet null zijn, wat kan er dan gedaan worden?

Ik zou kunnen doen

assert returnValue != null : "Not acceptable null value";

maar beweringen kunnen worden uitgeschakeld!

Dus is het oké om te doen

if(returnValue==null)
      {
           throw new NullPointerException("return value is null at method AAA");
      }

?

Of is het beter om een door de gebruiker gedefinieerde uitzondering (zoals NullReturnValueException ) te gebruiken voor een dergelijke voorwaarde?


Antwoord 1, autoriteit 100%

Ik zie er geen probleem in om een NPE zo vroeg mogelijk te gooien voordat de JVM het voor je doet – in het bijzonder voor null-argumenten. Hier lijkt enige discussie over te bestaan, maar er zijn veel voorbeelden in de Java SE-bibliotheken die precies dit doen. Ik zie niet in waarom NPE heilig zou moeten zijn in het aspect dat je het niet zelf kunt gooien.

Maar ik dwaal af. Deze vraag gaat over iets anders. Je hebt het over een post-conditie waarin staat dat de retourwaarde niet null mag zijn. Null zou in dit geval toch zeker betekenen dat je een bug in de methode zelfhebt?

Hoe zou je dit zelfs documenteren? “Deze methode genereert een NullPointerException als de geretourneerde waarde onverwacht null is”? Zonder uit te leggen hoe dit kon gebeuren? Nee, ik zou hier een bewering gebruiken. Uitzonderingen moeten worden gebruikt voor fouten die mogelijk kunnen gebeuren – niet om dingen te dekken die kunnen gebeuren als er iets mis is in de methode, want dat helpt niemand.


Antwoord 2, autoriteit 95%

Ik raad je aan om nooit zelf NullPointerExceptionte gooien.

De belangrijkste reden om dit niet te doen, zoals Thorbjørn Ravn Andersen in een opmerking hieronder zegt, is dat je ‘echte, slechte NPE’s’ niet wilt mixen met opzettelijk gegooide NPE’s.

Dus, totdat u zeker weet dat u ‘geldige’ NPE kunt herkennen, raad ik u aan IllegalArgumentExceptionte gebruiken wanneer u uw API-gebruiker wilt vertellen dat nullis geen geldige argumentwaarde. Het gedrag van uw methode bij het doorgeven van een illegale null-parameter moet worden gedocumenteerd.

Een andere (modernere imho) optie is om @NotNullannotatie bij het argument te gebruiken.
Hier is een artikel over het gebruik van @NotNull-annotatie.

Zoals ik eerder al zei, kunnen er ook gevallen zijn waarin het gooien van NPE niet verwarrend is voor jou of je teamgenoten: de oorzaak van NPE moet duidelijk en herkenbaar zijn.

Als je bijvoorbeeld een bibliotheek met een preconditions-module gebruikt, zoals Guava, dan vind ik het gebruik van checkNotNull()-achtige methoden een voorkeursmanier om illegaal om te gaan met – doorgegeven nullen.

checkNotNull(arg, msg)gooit NPE, maar uit de stacktrace is het vrij duidelijk dat het werd geproduceerd door Preconditions.checkNotNull()en dus is het geen onbekende bug maar eerder verwacht gedrag.


Antwoord 3, autoriteit 66%

Aangezien NullPointerExceptionde idiomatische manier is om een onverwachte null-waarde in Java te communiceren, zou ik u aanraden een standaard NullPointerExceptionte gebruiken en geen inlandse. Houd er ook rekening mee dat het principe van de minste verrassing zou suggereren dat u niet uw eigen uitzonderingstype uitvindt voor een geval waarin een systeemuitzonderingstype bestaat.

Beweringen zijn goed voor debugging, maar niet goed als je aan bepaalde voorwaarden moet omgaan, dus dat is niet echt een goede manier om de foutconditie aan te pakken.


4, Autoriteit 18%

Er is zeker geen universele wet tegen het gooien van nullpointerexceptie, maar het is moeilijk om te beantwoorden als je eigenlijk in zo’n geabstracteerd voorbeeld zou moeten zijn. Wat je niet wilt doen, is mensen de ketting opdagen in de positie van proberen om nullpointerexception te vangen. Code zoals dit (echt voorbeeld, ik zweer):

catch (NullPointerException npe) {
  if (npe.getMessage().equals("Null return value from getProdByCode") {
    drawToUser("Unable to find a product for the product type code you entered");
  } 
}

Is een trefzekere indicator dat je iets verkeerd doet. Dus als de null-retourwaarde een indicator is van een systeemstatus die u daadwerkelijk kunt communiceren, gebruik dan een uitzondering die die status communiceert. Er zijn niet veel gevallen die ik kan bedenken waarin het zinvol is om een referentie null te controleren om alleen maar een nullpointer te gooien. Gewoonlijk zou de volgende regel code toch de nullpointer (of iets meer informatiefs) hebben weggegooid!


Antwoord 5, autoriteit 14%

http://pmd.sourceforge.net/pmd- 5.0.1/rules/java/strictexception.html
“Vermijd het gooien van NullPointerExceptions. Deze zijn verwarrend omdat de meeste mensen zullen aannemen dat de virtuele machine het heeft veroorzaakt. Overweeg in plaats daarvan een IllegalArgumentException te gebruiken; dit zal duidelijk worden gezien als een door de programmeur geïnitieerde uitzondering.”


Antwoord 6, autoriteit 11%

Ik zou het gebruik van NullPointerException als oké beschouwen, alsje de beschrijving herinnert. Daar heeft de onderzoeker werk mee (regelnummers kunnen verschuiven). Vergeet ook niet te documenteren dat uw methoden in speciale gevallen null-pointeruitzonderingen genereren.

Als je je methodeparameters meteen aan het begin controleert, is een throw new IllegalArgumentException("foo==null")ook acceptabel voor mij.


Antwoord 7, autoriteit 9%

Als u een methodecontract beschrijft waarbij de retourwaarde niet nullkan zijn, kunt u er beter voor zorgen dat u geen nullretourneert. Maar dit is helemaal geen NullPointerException. Als de waarde die u moet retourneren nullis, heeft de beller u duidelijk slechte argumenten gegeven (IllegalArgumentException), bevindt u zich niet in een geldige staat (IllegalStateException), of er is een andere, veel betekenisvollere uitzondering opgetreden dan NullPointerException (wat meestal een programmeerfout aangeeft).


Antwoord 8, autoriteit 7%

Een boek dat ik O’Reilly’s Java in A Nutshellheb genoemd en dat is geschreven door een expert, geeft deze definitie voor NullPointerException:

Signaleert een poging om toegang te krijgen tot een veld of een methode van een null-object aan te roepen.

Aangezien het retourneren van null geen van beide is, denk ik dat het beter is om je eigen uitzondering te schrijven.


Antwoord 9, autoriteit 7%

De JavaDoc voor NullPointerExceptionstelt:

Gegooid wanneer een applicatie probeert om
gebruik null in een geval waarin een object is
verplicht. Deze omvatten:

* Calling the instance method of a null object.
* Accessing or modifying the field of a null object.
* Taking the length of null as if it were an array.
* Accessing or modifying the slots of null as if it were an array.
* Throwing null as if it were a Throwable value. 

Toepassingen moeten instanties van gooien
deze klasse om ander illegaal aan te geven
gebruik van het null-object.

Ik beschouw het schenden van de post-conditie een illegale actie. Ik denk echter welke uitzondering je gebruikt, doet er niet veel uit, omdat we het hebben over een codepad die (en hopelijk is) onbereikbaar, en dus je geen foutbehandelingspecifiek op die uitzondering hebt, en vandaar het enige effect Van die naam is een andere formulering van sommige invoer in een logbestand dat niemand waarschijnlijk zal zien.

Als u daarentegen denkt dat de postvoorwaarde waarschijnlijk wordt geschonden, is het misschien een goed idee om meer foutopsporingsinformatie op te nemen, zoals de argumenten waarmee de methode is ingeroepen.


10, Autoriteit 5%

absoluut ja.

Zelfs JDK7 las dit op. Zie objecten # eisenonNull

void doWith(final Object mustBeNotNull) {
    /*
    // bush style
    if (mustBeNotNull == null) {
        throw new IllegalArgumentException("mustBeNotNull must not be null");
    }
    */
    /*
    // obama style
    if (mustBeNotNull == null) {
        throw new NullPointerException("mustBeNotNull must not be null");
    }
    */
    // kangnam style
    Objects.requireNonNull(mustBeNotNull, "mustBeNotNull must not be null");
    assert mustBeNotNull != null;
}

11, Autoriteit 2%

IMO U MOET NOOIT EEN NULLPOINTEREXPLACCCESPECT MOETGEN. De routine zou niet weten of de echte of handmatige nullpointerexceptie zonder de beschrijving te controleren. In dit geval lijkt het erop dat u uw eigen uitzondering wilt rollen die overeenkomt met het probleem dat dichterbij komt, zodat de oproepmethode deze uitzondering correct kan herstellen. Misschien zou een postconditionexceptie al generiek genoeg zijn voor vele omstandigheden.


12, Autoriteit 2%

Het is vaak een heel goed idee om NPE te gooien voordat de logica zo diep wordt dat de bellende programmeur het moeilijk zal zijn om uit te zoeken wat null was. AddListener () Methoden zijn een goed voorbeeld.

Niet-geïnformeerde downvotes ondanks zijn er veel methoden in de JDK die precies dit doen.


13

In de Java-vers null is altijd een geldige waarde bij het verwachten van een object. Je bent beter af om dergelijke onmogelijke postcondities te vermijden. Als je echt niet een null kunt houden, moet je je methode opnieuw bewerken, zodat je een primitief kunt retourneren.


14

Zoals Joshua Bloch ooit zei: “NULL ZUIGT!” 🙂 Wanneer er null is, is mijn gezicht, ik probeer het optioneel te gebruiken dat Guava biedt. De voordelen zijn talrijk voor mij.


15

Wanneer er een post-conditie is, mag die retourwaarde van een methode niet null, wat kan worden gedaan?

Een postvoorwaarde betekent dat de betreffende methode een bug heeft als niet wordt voldaan. De manier om dit in code uit te drukken is door een assertop de post-conditie. Gooi direct een uitzondering, zoals een NullPointerExceptionof een IllegalStateException, zou een beetje misleiden, en dus misleid.

Is het goed om nullpointerexception te gooien?

Het Java API-document voor de NPE zegt ja, maar afgaande op de stemmen op deze pagina, zegt een 3:1 meerderheid van ontwikkelaars nee. Dus ik zou zeggen dat het afhangt van de conventies in je werkgroep.

Het API-document vermeldt eerst de gevallen waarin de JVM een NPE genereert omdat code probeert een bewerking op een null-referentie aan te roepen waarvoor een of ander object vereist is (zoals het aanroepen van een methode of toegang tot een veld), en nullis geen object. Er staat dan:

Applicaties moeten instanties van deze klasse genereren om ander illegaal gebruik van het null-object aan te geven.

Interessant is dat nullhier een »object« wordt genoemd, wat het niet is. Wat me eraan herinnert dat de naam NullPointerExceptional bizar is voor een taal die geen pointers heeft. (Dat had waarschijnlijk NullReferenceExceptionmoeten zijn, zoals in de Microsoft .NET klassenbibliotheek.)

Dus moeten we het API-document op dit punt afwijzen? Ik denk het niet. De klassenbibliotheek gebruikt de NPE zoals beschreven in de documenten, bijvoorbeeld in java.nio.channels:

Tenzij anders vermeld, zal het doorgeven van een null-argument aan een constructor of methode in een klasse of interface in dit pakket ervoor zorgen dat een NullPointerExceptionwordt gegenereerd.

Dit is geen NPE gegenereerd door de JVM, maar een gecodeerde NPE met een bijgevoegde foutmelding waarin staat welk argument nullwas (zoals "in" is null!) . (De code kan worden bekeken door javap -c -p java.nio.channels.Channels | morete doen, op zoek naar private static void checkNotNull.) En er zijn veel klassen die NPE’s op deze manier gebruiken, in wezen als een speciaal geval van IllegalArgumentException.

Dus na dit een beetje te hebben onderzocht en erover nagedacht, vind ik dit een goed gebruik van de NPE, en daarom ben ik het eens met het API-document en de minderheid van Java-ontwikkelaars (volgens de stemmen op deze pagina) dat je hebt zowel het recht als het recht om de NPE in je eigen code te gebruiken op dezelfde manier als de Java-klassebibliotheek, dat wil zeggen door een foutmelding te geven, die opvallend ontbreekt in door JVM gegenereerde NPE’s, daarom is het geen probleem om de twee te vertellen soorten NPE uit elkaar.

Om het kleine punt aan te pakken dat de NPE hoe dan ook verder op de weg zal worden gegooid: het kan heel logisch zijn om fouten vroeg op te vangen in plaats van de JVM door te laten gaan met het programma, mogelijk met schijf- of netwerk-I/O (en vertragingen), en het genereren van een onnodig grote stacktracering.


Antwoord 16

Ja, het is oké, maar ik zou zeggen dat het een betere beslissing is om het gewoon te laten gebeuren.

Het probleem met Java-programmeurs en null is dat mensen een C/C++-achtergrond hebben, waar NULL iets heel anders betekent. In C/C++ is dereferentie van een NULL (of wild) pointer een serieus probleem dat vreemde geheugenproblemen kan veroorzaken of uw programma kan laten crashen (uiteraard niet wenselijk). Als je uit de C/C++ manier van denken kunt komen en je realiseert je dat je deze extra laag hebt, de JVM, die deze aandoening voor je afhandelt, begin je een beetje anders over NULL te denken.

In C++ hebben we bijvoorbeeld referenties waaraan nooit NULL kan worden toegekend. In Java zijn er geen verwijzingen, maar Java-objectparameters gedragen zich meer als C++-aanwijzers. Maar er zijn veel situaties in Java waarin een methode impliciet NIETeen null-waarde voor een parameter zou moeten krijgen! Dus, wat doen we?

Het probleem met het behandelen van null in Java zoals je doet in C++ is dat dit resulteert in nulcontroles OVERAL, terwijl je in C++ gewoon een methode zou declareren om een referentie te nemen, waarin expliciet staat dat het accepteert geen NULL. Vrij snel moet elke methode een sanity check bevatten om de toestand van het programma op dat moment te bevestigen, waardoor er een puinhoop ontstaat.

Het is een veel betere gemoedstoestand om ervan uit te gaan dat het standaardcontract van een methode is dat null ongeldig is voor een parameterwaarde.

Waarom? Laten we eens kijken wat er gebeurt als een dergelijke methode null als parameterwaarde ontvangt. a) Misschien is het in orde omdat het de waarde niet verwerpt als onderdeel van zijn gedrag. In dit geval gebeurt er niets. b) De waarde is gederefereerd. In dit geval is het gedrag van de JVM precies wat we willen: er wordt een uitzondering gegenereerd die aangeeft dat het contract van de methode is geschonden omdat een parameterwaarde null is, en het bevat een stacktracering die ons helemaal naar de regel in de methode waar de waarde op deze manier wordt gebruikt.

Mensen nemen het probleem met NPE omdat ze denken dat wanneer je NPE in de logboeken ziet, het betekent “iemand fucked up”. Maar laten we hier een seconde over nadenken. Wat is eigenlijk het verschil in NPE als een indicator van fuckup in tegenstelling tot verwacht gedrag? Ik zou het grootste verschil (en voordeel) beweren van het gebruik van NPE zoals het verwachte gedrag is dat het niet wijst op de methode waarin het is opgetreden, maar aan de beller om het contract van de methode te overtreden. Dit is veel nuttiger informatie. Als we simpelweg nul zouden controleren en een andere uitzondering gooien, kunnen we onder de valse indruk zijn dat het waargenomen gedrag een verwachte fout is, wanneer de beller echt het contract van de methode schendt. Gefeliciteerd, u hebt correct geanticipeerd hoe u de beller zou kunnen verkleinen bij het oproepen van de methode – hoewel alles wat u maar hebt gedaan, dwaalt u op een dwaalspoor van wat de echte oorzaak van de uitzondering is – of op zijn best, u twee verschillende uitzonderingsklassen gebruikt om hetzelfde en massaal de code met onnodige afval in de tussentijd in te vissen.

Dus als het erop komt, beschouwen mensen NPE om taboe te zijn. Letterlijk zullen mensen het niet toestaan ​​om te worden gegooid omdat er een gevoel van schaamte is dat erbij past, alsof je niet slim genoeg bent omdat je niet probeerde te raden waar een waarde niet nul zou zijn. Nou, ik heb nieuws voor jullie, je schrijft gewoon meer nutteloze code om hetzelfde te doen.

Enkele voorbeelden:

public void foo(Object o) {
  if (o == null) {
    throw new IGotchaException("HA! You're an IDIOT! I knew it!!");
  }
  o.bar();
}
public void foo(Object o) {
  o.bar();
}

^ politiek anders. Functioneel, niet zo veel.

public void foo(int a, long b, double c, Object o) {
  if (o == null) {
    throw new IllegalArgumentException("Oh. Uh. Well, you've passed me null here. I... I'm not sure where to go from here because this object is kind of required for this function to do what it's supposed to do. Soooo... wouldja mind reworking your code a little bit so as to not pass null to this function as a parameter?! That'd be great thanks. Oh by the way, it's cause we deference o 40 lines below here");
  }
  // ...
  o.doSomethingWithA(a);
}
public void foo(int a, long b, double c, Object o) {
  // ...
  o.doSomethingWithA(a);
  // NullPointerException, line 40, e.g. it wasn't OK to pass null for o you lunkhead
}

^ Bespaart misschien een paar CPU-cycli ten koste van een hoop vervelende code. In het tweede geval doen we echter minder vergelijkingen.

public void foo(Object a, Object b, Object c, Object d) {
  if (a == null) throw IllegalArgumentException("jackass");
  if (b == null) throw IllegalArgumentException("jackass");
  if (c == null) throw IllegalArgumentException("jackass");
  // But d is totally OK!
  // ...
  c.setSomeValueThatMayBeNull(d);
}
public void foo(Object a, Object b, Object c, Object d) {
  // ...
  c.setSomeValueThatMayBeNull(d);
  // Throws null pointer exception if c is null, but not if d is null. Which is basically the same as above
}

^ Het contract is impliciet uit de verklaring, in plaats van een uitzonderingsgeval aan het begin van de methode. Biedt geen ander nadeel.

public void foo(Object o) {
  if (o == null) {
    doTheBoogie();
  } else {
    doTheRobot();
  }
}

^ Slecht

public void foo(Object o, int b) {
  Bar value = o.findSomethingWhichMayExist(b);
  if (value == null)
    return;
  value.doSomething();
}

^ gebruiken null retourwaarde het ontbreken van een waarde aan te geven. OK.

Een andere reden waarom mensen hebben problemen met NPE is omdat ze niet weten hoe om uitzonderingen te behandelen. NPE mag nooit een showstopper zijn. De juiste gedrag is om RuntimeException te vangen, vermoedelijk op een veel hoger (of lager, afhankelijk van hoe je het ziet) niveau in de call-stack dat de vallen het en rapporten voordat “main”. Dat wil zeggen, ervan uitgaand dat je het ontwikkelen van het soort programma dat moet veerkrachtiger te zijn en niet zomaar crash wanneer een NPE gebeurt.

Bottom line: niet ooit verwacht dat het een geldig ding te passeren in null waarden voor parameters van de methode. En zeker niet over een contract voor een methode die expliciet accepteert null en behandelt het als een geldige waarde niet te creëren. Maar, Toestaan ​​null pointer uitzonderingen te gebeuren, en laat de code niet, of niet mislukken als het maakt niet uit, natuurlijk.


17

Ik ben het eens met de claim in de eerdere antwoorden, dat de NPE is bug in de code en mag niet worden gegooid, maar de ontwikkelaar moet onverwachte null op te lossen. Echter kan deze staat het grootste deel van de tijd worden voorkomen door tests.

De vraag werd gesteld vóór 7 jaar, maar nu hebben we Optioneel in java 8 en deze functie te laten NPE te voorkomen.

De laatste oplossing, die in mijn gedachten heb is dat je object moet controleren op nul en als het is gelijk, dus gooi uw eigen uitzondering met een beschrijving van wat er gebeurd is.


18

Gooi deze uitzondering is niet een goede praktijk in sommige gevallen en ik vraag me af waarom wanneer u al op te vangen met de if?

if (returnValue == null)

Other episodes