it-swarm-eu.dev

Nejlepší způsob, jak zacházet s nuly v Javě?

Mám nějaký kód, který selhává kvůli NullPointerException. Volá se metoda objektu, kde objekt neexistuje.

To mě však vedlo k přemýšlení o nejlepším způsobu, jak to napravit. Musím vždy defenzivně kódovat pro null, abych zajistil budoucí zkušební kód pro výjimky pro nulové ukazatele, nebo bych měl opravit příčinu null tak, aby k ní nedocházelo po proudu.

Jaké jsou vaše myšlenky?

21
Shaun F

Pokud je null přiměřeným vstupním parametrem pro vaši metodu, opravte metodu. Pokud ne, opravte volajícího. „Rozumný“ je flexibilní termín, proto navrhuji následující test: Jak by měla metoda zpracovat nulové zadání? Pokud najdete více než jednu možnou odpověď, pak je null ne rozumný vstup.

45
user281377

Nepoužívejte hodnotu null, použijte volitelné

Jak jste zdůraznili, jeden z největších problémů s null v Java je to, že jej lze použít všude, nebo alespoň pro všechny referenční typy.

Je nemožné říci, že to může být null a co nemůže být.

Java 8 představuje mnohem lepší vzorec: Optional.

A příklad od společnosti Oracle:

String version = "UNKNOWN";
if(computer != null) {
  Soundcard soundcard = computer.getSoundcard();
  if(soundcard != null) {
    USB usb = soundcard.getUSB();
    if(usb != null) {
      version = usb.getVersion();
    }
  }
}

Pokud každá z nich může nebo nemusí vrátit úspěšnou hodnotu, můžete změnit API na Optional s:

String name = computer.flatMap(Computer::getSoundcard)
    .flatMap(Soundcard::getUSB)
    .map(USB::getVersion)
    .orElse("UNKNOWN");

Výslovným kódováním možnosti v typu budou vaše rozhraní mnohem lepší a váš kód bude čistší.

Pokud nepoužíváte Java 8, můžete se podívat na com.google.common.base.Optional v Google Guava.

Dobré vysvětlení týmu Guava: https://github.com/google/guava/wiki/UsingAndA vyhnúťingNullExplained

Obecnější vysvětlení nevýhod pro nulu, s příklady z několika jazyků: https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/


@ Nonnull, @Nullable

Java 8 přidává tyto anotace, aby pomohla nástrojům pro kontrolu kódu, jako jsou IDE, zachytit problémy. Jejich účinnost je značně omezená.


Zkontrolujte, kdy má smysl

Nezapisujte 50% kódu, který kontroluje null, zvláště pokud není nic rozumného, ​​co váš kód dokáže udělat s hodnotou null.

Na druhou stranu, pokud lze použít null a něco znamenat, nezapomeňte jej použít.


Nakonec samozřejmě nelze odstranit null z Java. Důrazně doporučujeme nahradit abstrakci Optional, kdykoli je to možné, a zkontrolovat null v jiných případech, kdy s tím můžete udělat něco rozumného.

21
Paul Draper

Existuje několik způsobů, jak to vyřešit, pepřování kódu pomocí funkce if (obj != null) {} není ideální, je chaotický, přidává šum při čtení kódu později během cyklu údržby a je náchylný k chybám, protože je snadné zapomenout k provedení tohoto balení kotlové desky.

Záleží na tom, zda chcete, aby kód pokračoval v tichém provádění nebo selhal. Je null chyba nebo očekávaný stav.

Co je null

V každé definici a případě Null představuje absolutní nedostatek dat. Null v databázích představují nedostatek hodnoty pro tento sloupec. null String není stejný jako prázdný String, null int není totéž jako ZERO, teoreticky. V praxi „záleží“. Prázdná String může udělat dobrou implementaci Null Object Pro třídu String, pro Integer záleží na obchodní logice.

Alternativy jsou:

  1. Vzor Null Object . Vytvořte instanci svého objektu, která představuje stav null, a inicializujte všechny odkazy na tento typ odkazem na implementaci Null. To je užitečné pro jednoduché objekty typu hodnoty, které nemají mnoho odkazů na jiné objekty, které by mohly být také null a očekává se, že budou null jako platný stav.

  2. Pomocí nástrojů zaměřených na poměr stran můžete propojit metody s aspektem Null Checker, Který zabrání tomu, aby byly parametry nulové. To je v případech, kdy null je chyba.

  3. Použijte assert() o nic lepší než if (obj != null){}, ale méně šumu.

  4. Použijte nástroj pro vymáhání smluv, například Contracts for Java . Stejný případ použití jako něco jako AspectJ, ale novější a místo externích konfiguračních souborů používá anotace. To nejlepší z obou aspektů a hledisek.

1 je ideálním řešením, když je známo, že příchozí data jsou null a je třeba je nahradit nějakou výchozí hodnotou, takže spotřebitelé proti proudu se nebudou muset vypořádat se všemi nulovými kontrolními kódy. Expresivnější bude i kontrola oproti známým výchozím hodnotám.

2, 3 a 4 jsou pouze vhodnými alternativními generátory výjimek, které nahrazují NullPointerException něčím více informativním, což je vždy a vylepšení.

Na konci

null v Java je téměř ve všech případech logická chyba. Vždy byste se měli snažit eliminovat kořenovou příčinu NullPointerExceptions. Měli byste se snažit nepoužívat null podmínky jako obchodní logika. if (x == null) { i = someDefault; } pouze provede počáteční přiřazení této výchozí instance objektu.

8
user7519

Přidání nulových kontrol může způsobit testování problematické. Podívejte se na tuto skvělou přednášku ...

Podívejte se na přednášku o přednáškách na téma Techtech Google: „Diskuse o čistém kódu - nehledejte věci!“ mluví o tom kolem minuty 24

http://www.youtube.com/watch?v=RlfLCWKxHJ0&list=PL693EFD059797C21E

Paranoidní programování zahrnuje přidání nulových kontrol všude. Vypadá to jako dobrý nápad zpočátku z hlediska testování, takže je obtížné se vypořádat s testováním typu null check.

Také, když vytvoříte předpoklad pro existenci nějakého objektu, například

class House(Door door){

    .. null check here and throw exception if Door is NULL
    this.door = door
}

brání vám ve vytváření domu, protože vyhodíte výjimku. Předpokládejme, že vaše testovací případy vytvářejí falešné objekty pro testování něčeho jiného než dveří, to nemůžete udělat, protože jsou vyžadovány dveře

Ti, kteří trpěli Mockovým stvořením, si jsou dobře vědomi těchto typů nepříjemností.

Stručně řečeno, vaše testovací sada by měla být dostatečně robustní, aby mohla otestovat dveře, domy, střechy nebo cokoli, aniž by o tom byla paranoidní. Jak vážně je obtížné přidat nulový kontrolní test pro konkrétní objekty ve vašem testování :)

Vždy byste měli upřednostňovat aplikace, které fungují, protože máte několik testů, které prokazují, že to funguje, než HOPING, že to funguje jednoduše proto, že máte celou řadu předběžných nulových kontrol všude.

8
Constantin

tl; dr - Je dobré kontrolovat neočekávané nulls, ale BAD pro aplikaci, aby se pokusil udělat je dobrý.

Detaily

Je zřejmé, že existují situace, kdy null je platným vstupem nebo výstupem metody, a další tam, kde není.

Pravidlo č. 1:

Javadoc pro metodu, která umožňuje parametr null nebo vrací hodnotu null, to musí jasně dokumentovat a vysvětlit co znamená null.

Pravidlo č. 2:

Metoda API by neměla být specifikována jako přijetí nebo vrácení null, pokud k tomu není dobrý důvod.

Vzhledem k jasné specifikaci „smlouvy“ metody „vis-a-vis nulls, je programovací chyba předat nebo vrátit null, kde byste neměli.

Pravidlo č. 3:

Aplikace by se neměla pokoušet „opravit“ chyby v programování.

Pokud metoda detekuje null, která by tam neměla být, neměla by se pokusit problém vyřešit tak, že ji změní na něco jiného. To jen skrývá problém před programátorem. Místo toho by měl umožnit NPE, aby se stalo, a způsobit selhání, aby programátor mohl zjistit, co je hlavní příčina, a opravit ji. Doufejme, že k chybě dojde během testování. Pokud ne, říká to něco o vaší metodice testování.

Pravidlo č. 4:

Pokud je to možné, napište kód, abyste včas zjistili chyby programování.

Pokud máte v kódu chyby, které mají za následek mnoho NPE, nejtěžší věcí může být zjistit, odkud pocházejí hodnoty null. Jedním ze způsobů, jak usnadnit diagnostiku, je napsat kód tak, aby byl null detekován co nejdříve. Často to můžete udělat ve spojení s jinými kontrolami; např.

public setName(String name) {
    // This also detects `null` as an (intended) side-effect
    if (name.length() == 0) {
        throw new IllegalArgumentException("empty name");
    }
}

(Existují zjevně případy, kdy by pravidla 3 a 4 měla být zmírněna realitou. Například (pravidlo 3), některé druhy aplikací se musí pokusit pokračovat po detekování pravděpodobně programových chyb. A (pravidlo 4) přílišná kontrola špatných parametrů může mít dopad na výkon.)

4
Stephen C

Doporučil bych, aby byla metoda defenzivní. Například:

String go(String s){  
    return s.toString();  
}

Mělo by to být více v souladu s tímto:

String go(String s){  
    if(s == null){  
       return "";  
    }     
    return s.toString();  
}

Uvědomuji si, že je to naprosto triviální, ale pokud invokátor očekává, že jim objekt dá výchozí objekt, který nezpůsobí předání nulové hodnoty.

3
Woot4Moo

Následující obecná pravidla o nulové mě doposud hodně pomohla:

  1. Pokud data pocházejí mimo vaši kontrolu, systematicky kontrolujte nulové hodnoty a postupujte náležitě. To znamená, že vyvoláte výjimku, která má smysl pro funkci (zaškrtnutá nebo nezaškrtnutá, stačí se ujistit, že název výjimky přesně říká, co se děje). Ale NIKDY neztratte ve svém systému hodnotu, která by mohla přinést překvapení.

  2. Pokud je Null v doméně příslušných hodnot pro váš datový model, vypořádejte se s ním náležitě.

  3. Při vracení hodnot zkuste nevracet nuly, kdykoli je to možné. Vždy dávejte přednost Prázdným seznamům, prázdným řetězcům, vzorům nulových objektů. Pokud je to nejlepší možná reprezentace dat pro daný případ použití, ponechte hodnoty Null jako vrácené hodnoty.

  4. Pravděpodobně nejdůležitější ze všech ... Testy, testy a testy znovu. Když testujete váš kód, netestujte jej jako kodér, otestujte jej jako dominanta nacistických psychopatů a pokuste se představit si různé způsoby, jak z tohoto kódu mučit peklo.

To má tendenci na paranoidní straně, pokud jde o nuly, které často vedou k fasádám a proxy serverům, které propojují systémy s okolním světem, a přísně kontrolované hodnoty uvnitř s hojnou redundancí. Vnější svět zde znamená skoro všechno, co jsem sám nekódoval. To nese náklady za běh, ale zatím jsem jen zřídka musel optimalizovat to vytvořením "nulové bezpečné sekce" kódu. Musím však říci, že většinou vytvářím dlouhodobě fungující systémy pro zdravotnictví a poslední věcí, kterou chci, je subsystém rozhraní přenášející vaše jodové alergie na CT skener havaruje kvůli neočekávanému nulovému ukazateli, protože někdo jiný v jiném systému si nikdy neuvědomil, že jména by mohla obsahují apostrofy nebo znaky jako 但 耒耨。

tak jako tak .... moje 2 centy

2
Newtopian

Navrhl bych použít vzorec Option/Some/None z funkčních jazyků. Nejsem specialista Java, Java), ale intenzivně používám svou vlastní implementaci tohoto vzoru v mém projektu C # a jsem si jist, že by mohl být převeden na Java svět.

Myšlenka za tímto vzorcem je: pokud je logicky situace, kdy existuje možnost zmizení hodnoty (například při návratu z databáze pomocí id), poskytnete objekt typu Option [T], kde T je možná hodnota . I případ nepřítomnosti hodnotového objektu třídy Žádný [T] se nevrátil, v případě, že se vrátila existence hodnoty - objekt Nějakého [T] obsahující hodnotu.

V tomto případě musíte zvládnout možnost absence hodnoty a pokud provedete kontrolu kódu, můžete snadno najít místo nesprávného zacházení. Inspiraci z implementace jazyka C # najdete v mém úložišti bitbucket https://bitbucket.org/mikegirkin/optionsomenone

Pokud vrátíte nulovou hodnotu a je logicky ekvivalentní chybě (například neexistuje žádný soubor nebo se nemohlo připojit), měli byste vyvolat výjimku nebo použít jiný vzor pro zpracování chyb. Myšlenka za tím opět skončí s řešením, když musíte vyřešit situaci absence hodnoty a snadno najít místa nesprávného zacházení v kódu.

1
Hedin
  1. Nepoužívejte volitelný typ, pokud to není skutečně volitelné, často je výstup lépe zpracováván jako výjimka, pokud jste skutečně neočekávali, že bude jako možnost neplatný, a ne proto, že pravidelně píšete kód buggy.

  2. Jak ukazuje článek Google, problém není null jako typ, který má své použití. Problém je v tom, že nuly by měly být kontrolovány a zpracovávány, často je lze elegantně opustit.

  3. Existuje celá řada nulových případů, které představují neplatné podmínky v oblastech mimo běžnou činnost programu (neplatný vstup uživatele, problémy s databází, selhání sítě, chybějící soubory, poškozená data), což jsou důvody, pro které jsou zkontrolovány výjimky, manipulace s nimi, dokonce i pokud je to jen pro přihlášení.

  4. Zpracování výjimek je povoleno různé provozní priority a oprávnění v JVM na rozdíl od typu, jako je volitelné, což dává smysl pro výjimečnou povahu jejich výskytu, včetně včasné podpory pro zpožděné načtení popisovače do paměti, protože nemáte potřebují to pořád viset.

  5. Nemusíte psát nulové popisovače všude, pouze tam, kde k nim pravděpodobně dojde, kdekoli máte potenciální přístup k nespolehlivým datovým službám, a protože většina z nich spadá do několika obecných vzorců, které lze snadno abstrahovat, opravdu potřebujete pouze volání obsluhy, s výjimkou vzácných případů.

Takže myslím, že moje odpověď by byla zabalena do kontrolované výjimky a zpracována, nebo opravte nespolehlivý kód, pokud je to ve vaší schopnosti.

0
J-Boss

Pokud je jedním z možných výsledků vaší metody nulová hodnota, měli byste za to kódovat defenzivně, ale pokud má metoda vrátit nenulovou hodnotu, ale není, opravil bych to s jistotou.

Jako obvykle to záleží na případě, jako u většiny věcí v životě :)

0
jonezy

Knihovny lang Apache Commons poskytují způsob zpracování nulových hodnot

metoda defaultIfNull ve třídě ObjectUtils vám umožňuje vrátit výchozí hodnotu, pokud je předaný objekt nulový

0
Mahmoud Hossam