NetAcademia

A legjobbakat tanítjuk!

Miért ne használjunk NULL-t?

2017. május 30. 09:58 - Plesz Gábor

Yegor Bugayenko (Most futottam bele, sok dolgot egyelőre nem tudok róla, de van például meggyőző a Stack Overflow profilja) cikke Java példakódokkal illusztrált részletes összefoglalás arról, hogy miért ne használjunk null-t, és hogy kerüljük el, ha valamiért felmerül, hogy mégis használni kéne.

A blogja mondhatni elég határozott irányvonalú, valószínűleg nem mindenki egyetértését nyeri el, de szerintem egy aranybánya, rengeteg érdekes gondolkodnivaló található itt.

"A simple example of NULL usage in Java:

public Employee getByName(String name) {
  int id = database.find(name);
  if (id == 0) {
    return null;
  }
  return new Employee(id);
}

What is wrong with this method?

..."

Why NULL is Bad?

10 komment

A bejegyzés trackback címe:

https://netacademia.blog.hu/api/trackback/id/tr3012550123

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Gerilgfx 2017.05.31. 00:50:31

attól, hogy láttál egy cikket angolul, még nem kell valamiféle szent igazságnak képzelni, ezzel csak a saját önálló gondolatiságodat sajnálod le. szerintem a cikk címe is híbás, helyesen így hangzott volna: ,,Miért ne használjunk Java-t?''

Plesz Gábor · https://www.netacademia.hu/Oktato/PleszGabor 2017.05.31. 10:19:42

@Gerilgfx: Igazán köszönöm a visszajelzést :)

Sok érdekes dolog felmerült így, hasznos lehet, ha beszélünk ról.

1. Teljesen egyetértek azzal, hogy ha valaki csak egy cikket látott egy adott témában és angolul, akkor vigyáznia kell, mert könnyen előfordulhat az, hogy túlságosan is befolyásolja a véleményét.

Szerintem ráadásul a helyzet az, hogy az Informatikában felmerülő gondolatok túlnyomó része -a többség számára elérhető módon- angolul jelenik meg. Így az angol nyelvű befolyásolást elkerülni nem jó stratégia, tehát: a fenti gondolat bizony nagyon aktuális.

2. Kis kitérő: sok információ jön szembe nap mint nap, _én_ ezen a blogon általában azokat teszem fel, amikkel kapcsolatosan az érzésem az, hogy fontos róla tudni, vagy érdemes elolvasni, vagy frappánsan elemez valamit. Ez a cikk is ilyen. De ez az egész személyes, _én_ látom így, és annak tudatában teszem mindezt, hogy nem biztos, hogy más is ezt gondolja. Ezért nagyon értékes számomra minden visszajelzés.

A konkrét témával kapcsolatosan a következőt gondolom.

3. Aki már egy ideje programozik, annak előbb-utóbb vegyes érzései lesznek a NULL érték használatával kapcsolatosan. Nem véletlenül, az iparágban szerintem nagyjából konszenzus van arról, hogy -sarkosan fogalmazva- ahol lehet kerüljük a NULL használatát (NULL object pattern: hu.wikipedia.org/wiki/Null_Objektum_programtervez%C3%A9si_minta).

A blogbejegyzésben hivatkozott cikkben hivatkozott cikk (Null References: The Billion Dollar Mistake: www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare) nagyon szépen körüljárja kérdést és a NULL történetét.

4. Azonban a hivatkozások feldolgozása komolyabb befektetést kíván, és nem ad azonnal használható receptet egy-egy helyzetre. A hivatkozásokhoz képest viszont a blogolt cikk _szerintem_ egy átlagos progamozó számára is érthetően mutat használható módszereket, így felkeltette érdeklődésemet, remélve, hogy más is hasznosnak találja:)

5. Utolsó gondolat: tisztelem a határozottságot, sokszor hasznos. És nem az én dolgom a JAVA-t védeni, mert nem is értek hozzá. Jómagam a JAVA nyelvvel -azon kívül, hogy tanultam valaha- C# programozóként sokáig nem is találkoztam.

Az elmúlt években azonban szembesültem azzal, hogy egészen elképesztő eredményei vannak (például az ElasticSearch stack: www.elastic.co/, de lehetne hosszan sorolni), rengeteg kíváló programozó dolgozik vele, és amit csinálnak az bizony sokszor egyedülálló. A .NET világban mozgó emberként _nekem legalábbis_ van mit tanulnom tőlük.

Így én magam általában sem merek ilyen határozott véleményt alkotni, de most nem is értek egyet a véleményeddel.

Gerilgfx 2017.05.31. 15:09:19

@Plesz Gábor (NetAcademia): procedurális nyelvekben, pl C is van null (nagybetűvel, NULL), ott tulajdonképpenegy #dfine NULL (void*)0 formájában szokott implementálva lenni, és pontosan így és ilyen értelemben használjuk, mert egyszerűbb leírni, mintha a nullát castelgetnéd pointerré.

deklarálásnál érdemes értékként megadni a pointernek, hogy nehogy memóriaszemét legyen benne akkor, ha később nem adsz neki értéket (tehát char * eleresi_ut=NULL; .) továbbá, hiba esetén remekül vissza lehet dobni a NULL-t, illetve ha valahol nem akarunk értéket adni (például a függvény valamelyik bemeneti értékének értéknek NULL-t adunk, jelezve például azt, hogy mondjuk átadtunk egy felhasználói listát, de például az e-mail címek listáját nem ismerjük, ezért ott NULL-t adtunk át.). vagy például ha a kód későbbi részén nem tudjuk előre megjósolni, hogy egy pointernek van -e már rendes értéke, vagy még mindig NULL-e.

C-ben tehát egyértelműen, és jól működik a NULL. szóval szerintem hogyha más nyelvben nem működik ez jól, akkor az ott egyáltalán nem a NULL hibája, hanem sokkal inkább magával a programozási nyelvvel van a probléma. esetleg a bejegyzés címe lehetne még: miért ne használjunk null-t javaban, vagy xyz másik nyelvben, megemlítve, hogy eközben milyen jól és triviális a C-ben történő használata.

Plesz Gábor · https://www.netacademia.hu/Oktato/PleszGabor 2017.06.01. 12:00:01

@Gerilgfx: ez egy nagyon jó szempont, köszönöm!

Azt hiszem most már, hogy nagyon hasonló dolgokról beszélünk. A C#-ban (és ha jól tudom a JAVA nyelven is) a NULL értéket referenciát tartalmazó változó veheti fel. Akkor veszi fel, ha nincs beállítva a referencia objektumpéldányra. Ha jól gondolom, ezzel nagyon hasonló a működése az általad leírtakkal.

A probléma ezzel a következő.

Ha egy változó NULL értéket vehet fel, akkor minden esetben, mielőtt használnánk, ellenőrizni kell. Tehát meg kell nézni, hogy NULL értéke van-e, és ha igen, ennek megfelelően kezelni. Ha pedig a referencia mutat valahova, felhasználni az értékét, ahogy eredetileg is terveztük.

A példádnál maradva, ha az e-mail címek listája null, akkor nem csinálunk vele semmit, ha pedig mutat valahova, akkor feldolgozzuk.

Ez az esetszétválasztás a probléma, ami miatt a null értékek használatát érdemes meggondolni. Ezzel kapcsolatosan a null object pattern azt mondja, hogy ha például egy listánk van, akkor üres lista esetén ne nullt adjunk neki, hanem egy üres listát. Így a programunk végig tud menni az e-mail címek listáján, és mivel az üres, nem csinál semmit.

A lényeg tehát, hogy ne legyen esetszétválasztás a változó használata előtt, mert ha ezt egyszer elfelejtjük, akkor futásidejű hibával elszállunk.

Általánosabban pedig ez a minta azt tanácsolja, hogy null érték helyett használjunk olyan példányt, amivel elérjük, hogy ne kelljen esetszétválasztást végeznünk. Persze ez egyáltalán nem egyszerű dolog, ezért is örültem a cikknek, amikor a konkrét példáit megláttam.

Röviden ennyi, persze egy gyakorlott programozó a null ellenőrzést (általában) nem felejti el, de az ördög azért nem alszik.

Gerilgfx 2017.06.01. 14:18:35

@Plesz Gábor (NetAcademia): nos igen, ez egy nagyon komoly design flaw az ooop (overly-objektumorientált) nyelvek nagy részében, hisz lehet valami mondjuk "", 0, null, inicializálatlan, stb, és ezek kb mind külön dolgok, mindet le kell kezelni, ezért mindegyik tovább növeli a szopás-faktort. de c-ben ez nincs, ott nincs nyelvi szinten se lista, se objektum, csak változók, és azokban számok (a pointer is csak egy szám, a szöveg egy pointer, a NULL csak egy define 0-ára). szóval eleve teljesen más koncepció szerint építed fel a programot. cben mondjuk minden hardverközeli bitrágás, javaban meg magas szintű nyelvi elemeket kombinálsz össze. és nagyon nem mindegy, hogy melyikből akarod (tudod) kihagyni a nullt.

eMeL · http://emel.blog.hu/ 2017.06.03. 00:07:11

Igazából semmi baj nincs a NULL-al.
Valóban vannak problémák a null használata miatt, amikre jó lenne megoldásokat kitalálni, de a null léte fontos, olyannyira hogy pl. C#-ban még a nulllable értéktípusok is bevezetésre kerültek

Az iagazán j megoldást a non-nullable módosító bevezetése fogja meghozni, tudtommal már C#7-re is szerették volna, de esélye sem volt, de mindenesetre komolyan bekerült a gondolat a gondolkodásba.

twistedoakstudios.com/blog/Post330_non-nullable-types-vs-c-fixing-the-billion-dollar-mistake

.

bunny.hu · http://www.divecenter.hu 2017.06.25. 09:44:31

@Gerilgfx:
"nos igen, ez egy nagyon komoly design flaw az ooop (overly-objektumorientált) nyelvek nagy részében, hisz lehet valami mondjuk "", 0, null, inicializálatlan, stb, és ezek kb mind külön dolgok, mindet le kell kezelni, ezért mindegyik tovább növeli a szopás-faktort. "

Sokan szeretik fikázni a php-t, de ott pl. van erre egy frankó empty() függvény, ami kiválóan lekezeli a sokféle üreset. Más nyelven megírni sem ördöngősség. Egyébként én nagyon nem kedvelem ,ha valaki fikáz egy nyelvet, legyen az java, php vagy épp basic. Én azt vallom, hogy egy jó programozó bármilyen nyelvet használva is jó programozó marad, mert az a gondolkodásmódtól függ és nem az eszköztől. Az eszköz -ezesetben a nyelv- feladathoz való megválasztása pedig szintén a jó programozó ismérve.

Egyébként szerintem a cikk igenis elgondolkoztató, mert tényleg értelmesebb elkerülni a NULL-t a legtöbb esetben, és inkább végig gondolni, milyen módon lehetne olyan választ -vagy paramétert- adni, ami hasonló eredményt hoz, lásd a kolléga által is említett lista esetén null helyett üres lista.

Sealka 2017.08.28. 00:36:48

@Plesz Gábor (NetAcademia): Ilyen a példa manapság lehetetlen, ugyanis kézzel nem szoktunk objektumokat létrehozni, hanem ez egy függőség, amit a megfelelő DI keretrendszer előállít és maga a probléma fel sem merülhet. A null-t meg kell hagyni ezeknek az alacsonyszintű keretrendszereknek, de az alkalmazásban mi már ilyenekkel nem foglalkozunk, tehát maga a téma is értelmetlen a mi szintünkön. Ha ez nincs így az architektúrális/tervezési probléma és ott kisebb gond is nagyobb annál, minthogy kell e a null, vagy sem.

eMeL · http://emel.blog.hu/ 2017.12.20. 15:26:57

@nagy1: Tudomásul kell venni, hogy a "nagy igazság"... na az nem létezik.

Az alapelvek.
1./ A null szükséges, ha a váétozó definiáláskor nem tudunk azonnal értéket adni. Ilyen esetben nem elkerülhető a léte.
2./ A null praktikus, ha kapcsoló értékként kezeljük, az objektuk érvénytelen vagy adott tartalmú.
Egy hasznos eszköz (ésszel használva) nem véletlen, hogy a C# az érték típusokat is kibővítette nullable lehetőséggel.
3./ A null nagyon kellemetlen probléma okozó, mivel a kapott objektumot validálni kell és ez eddig csak kellemetlen, de meg kell tervezni milyen működés legyen, ha mégiscsak null paraméter érték érkezett.
Innen nem egyszerű mert ugye vagy nem veszi figyelembe (tipikus JS/PHP megközelítés, valami defaulttal megy tovább) és adatvesztést eredményezhet ez a mód. Bagy pl. egy exceptionnal megszakad a folyamta és ezt is le kell kezelni illetve keresni a probléma okát (miért is jelenik itt meg a null).

A C# új verziója adja majd a jó megoldást a 'non nullable' értelmezésű objektum adattípus, ami ugye 1./ esetén nem megoldás (akkor explicit jelezni kell a nullable jelzőt) és értelem szerűen lekezelni a null lehetőséget, de egy új rétegbe a validálás után már csak non nullable objektumok mehetnek tovább.
süti beállítások módosítása