Java - mi a nullpointerexception és hogyan kell kijavítani, kód q - a Russian (en)

Ha egy referenciaváltozót (vagyis egy objektumot) deklarál, akkor ténylegesen mutatót hoz létre az objektumhoz. Tekintsük a következő kódot, amelyben egy primitív típusú változót deklarálunk.

Ebben a példában az x változó az int és a Java inicializálja a 0 értéket. Amikor a második sorra a 10-et hozzárendeli, a 10-es értéket az x-hez kijelölt memóriahelyre kell írni.

De ha referenciatípust próbálsz deklarálni, akkor valami más történik. Tegye a következő kódot:

Az első sor egy változónak nevezett változót deklarálja. de nem tartalmaz primitív értéket. Ehelyett egy mutatót tartalmaz (mert az Integer típusa referenciatípus). Mivel még nem mondtad el, mit kell mutatni a Java-ra, az értéket nulla értékre állítja be, ami azt jelenti, hogy "nem adok meg semmit".

A második sorban az új kulcsszó az Integer típusú objektum létrehozására (vagy létrehozására) szolgál, és a változó mutatószámot hozzárendeli ehhez az objektumhoz. Most az objektumra hivatkozhat a dereferencing operátor segítségével. (Dot).

A kivétel, amelyet kértél, akkor emelkedik, amikor egy változót deklarál, de nem hoz létre objektumot. Ha megpróbálsz dereference num létrehozni egy objektumot, kapsz egy NullPointerException-et. A legkritikusabb esetekben a fordító elkapja a problémát, és elmondja neked, hogy "num nem lehet inicializálni", de néha olyan kódot írsz, amely nem közvetlenül hozza létre az objektumot.

Például a következő módszerrel rendelkezhet:

Ebben az esetben nem hoz létre obj objektumot. inkább azt feltételezve, hogy a doSomething doSomething módszer előtt hozták létre. Sajnos ez a módszer a következőképpen nevezhető:

Ebben az esetben az obj nulla. Ha a módszer szándékában áll megtenni valamit az elhaladt objektummal, ajánlatos a NullPointerException beadni, mert programozó hiba, és a programozónak szüksége lesz erre az információra hibakeresési célokra.

Alternatívaként előfordulhatnak olyan esetek is, amikor a módszer célja nem csak az átruházott objektummal való együttműködés, ezért az null paraméter elfogadható. Ebben az esetben ellenőriznie kell a null paramétert, és másképpen kell viselkednie. Ezt a dokumentációban is meg kell magyaráznod. Például a doSomething lehet írni:

Végül, hogyan lehet meghatározni a kivétel helyét és felhívni a Stack Trace használatát

A NullPointerException kivétel egy olyan kivétel, amely akkor fordul elő, ha megpróbál referenciát használni, amely azt jelzi, hogy nincs helye a memóriában (null), mintha egy objektumra hivatkozna. Ha a módszert null referenciára hívja, vagy megpróbálja elérni az null referenciamezőt, akkor a NullPointerException nevet hívja. Ezek a leggyakoribbak, de más módszerek szerepelnek a javadoc NullPointerException oldalon.

Valószínűleg a kód leggyorsabb példája a NullPointerException szemléltetésére szolgálhat. valósítja meg:

Jó kiindulópont a JavaDocs. Ezek a következők:

Ez akkor kerül dobásra, ha az alkalmazás megpróbál nullot használni, ha egy objektum szükséges. Ezek a következők:

  • Hívja a nulla objektum példányának módját.
  • A nulla objektum elérése vagy módosítása.
  • Null hossza, mintha egy tömb volt.
  • A résidők elérése vagy módosítása null, mintha tömb lenne.
  • Zéróérték eldobása, mintha egy Throwable érték lenne.

Az alkalmazásoknak ebbe az osztályba tartozó példányokat kell lerázniuk a null objektum másik illegális használatára való utalásra.

Az is előfordul, hogy ha szinkronizált null referenciát próbál használni. ez a JLS kivételét is kiveti.

  • Ellenkező esetben, ha az Expression értéke nulla, akkor a NullPointerException.

Tehát van NullPointerException. hogyan oldja meg? Nézzünk egy egyszerű példát, amely a NullPointerException-ot hívja

Határozzuk meg a nulla értékeket

Itt látjuk, hogy a kivétel a 13. sorban lett kiválasztva (a printString módszerben). Nézze meg a vonalat, és ellenőrizze, hogy mely értékek nullák a naplózási utasítások hozzáadásával vagy egy hibakereső segítségével. Megállapítottuk, hogy az s null, és a hossztengely módszerének megadása kivételt képez. Látjuk, hogy a program leáll egy kivételt, amikor az s.length () el lett távolítva a módszerről.

Nyomon követés, amelyből ezek az értékek származnak

Ezután ellenőrizze, honnan származik ez az érték. A módszer hívásait követve látjuk, hogy s nyomtatódik a printString (név) segítségével a print () metódusban. és ez a név null.

Nyomon követés, ahol ezeket az értékeket be kell állítani

Hol van megadva? A setName-ban (String). Néhány további hibakereséssel kapcsolatban látjuk, hogy ez a módszer egyáltalán nem szól. Ha ezt a módszert hívta meg, ellenőrizze az ilyen módszerek hívási sorrendjét, és a beállított módszert nem hívja meg a nyomtatási módszer után.

Ez elég ahhoz, hogy megoldást nyújtsunk: a nyomtatóhoz.setName () meghívását a printer.print () meghívása előtt kell hozzáadni.

A változónak lehet egy alapértelmezett értéke (és a setName megakadályozhatja, hogy null legyen):

A nyomtatási módszer vagy a printString ellenőrizheti a null értéket. például:

Vagy létrehozhat egy osztályt, hogy a név mindig nem nulla értékű legyen.

Ha problémát próbált hibakereséssel megoldani, és még mindig nincs megoldása, akkor további segítséget adhat a kérdésnek, de ne felejtse el bevenni az eddig megpróbáltatásokat. Legalább tartalmazzunk stacktrace-t a kérdésben és jelöljük meg a kódban lévő fontos sorszámokat. Próbálja meg először egyszerűsíteni a kódot (lásd: SSCCE).

K: Mi a NullPointerException?

Mint tudnod kell, a Java típusok primitív típusúak (logikai, int, stb.) És referenciatípusok. A Java-referenciatípusok lehetővé teszik, hogy egy speciális null értéket használjunk, amely egy olyan Java-módszer, amely "nem objektumot" mond.

NullPointerException futás közben, amikor a program megpróbálja használni nullot, mintha valódi referencia lenne. Például, ha ezt írja:

A "HERE" feliratú operátor megpróbálja végrehajtani a length () metódust null referenciában, és ez a NullPointerException nevet fogja hívni.

Sokféleképpen használhat null értéket, ami NullPointerException eredményt ad. Ha az a tény, hogy az NPE előfordulása nélkül egyetlen nullával is megtehető:

Kérdés: Honnan tudom az NPE stacket?

Tegyük fel, hogy fordítom és futtatom a fenti programot:

Első megfigyelés: a fordítás sikeres! A probléma a programban NEM fordítási hiba. Ez egy futásidejű hiba. (Néhány IDE figyelmezteti Önt, hogy a program mindig kivételt fog adni, de a standard javac fordító ezt nem teszi meg.)

Második megfigyelés: amikor a programot futtatom, két sor "gobbledy-gook" -ot jelenít meg. ROSSZT! Ez nem gyengéd. Ez a stacktrace. és fontos információkat szolgáltat. amely segít a kódhoz tartozó hiba nyomon követésében, ha időt vesz igénybe, hogy alaposan elolvashassa.

Lássuk tehát, hogy mit mond:

A stack nyomvonal első sora néhány dolgot mond:

  • Megadja a Java szál nevét, amelyben a kivételt választotta. Egy egyszerű, egy menetes programhoz hasonlóan "alap" lesz. Menjünk tovább.
  • Megmutatja a kiválasztott kivétel teljes nevét; Ie java.lang.NullPointerException.
  • Ha a kivételhez kapcsolódó hibaüzenet jelenik meg, akkor ez megjelenik a kivétel neve után. E tekintetben a NullPointerException szokatlan, mert ritkán van hibaüzenet.

A második sor a legfontosabb az NPE diagnózisában.

Ez néhány dolgot mond:

  • A "Test.main" -ben azt mondja, hogy a teszt osztály fő módszere volt.
  • A "Test.java:4" megadja az osztály forrásfájlnevét, és azt mondja, hogy az állítás, hol történt, a fájl 4. sorában szerepel.

Megjegyezzük, hogy bonyolultabb példában sok sor van az NPE stack nyomában. De biztos lehet benne, hogy a második sor (a sor első sora) megmondja, hol dobta el az NPE 1-et.

Röviden, a stacktrace egyértelműen megmondja nekünk, hogy az NPE program melyik programját dobta ki.

1 - Nem egészen rendben. Vannak dolgok, amelyeket egymásba ágyazott kivételeknek neveznek.

Kérdés: Hogyan állapítható meg az NPE kivétel oka a kódomban?

Ez nehéz rész. A rövid válasz az, hogy logikus következtetést alkalmaz a stack nyomvonal, a forráskód és a megfelelő API dokumentáció által szolgáltatott bizonyítékokra.

Először példázzunk egy egyszerű példát (lásd fent). Kezdjük azzal, hogy megvizsgáljuk azt a vonalat, amelyről a stacktrace-ról beszéltünk, ahol az NPE történik:

Hogyan okozhat ez NPE?

Valójában csak egy út van: ez csak akkor történhet meg, ha a foo nulla. Aztán próbáljuk futtatni a length () metódust null és. BANG!

De (azt hallottam, hogy azt mondod), hogy ha egy NPE-t a hosszú () metódusra hívtak be.

Nos, ha ez megtörténik, a köteg más lesz. Az "at" első sor azt jelzi, hogy a kivétel a java.lang.String osztály egy sorában lett kiválasztva. és a Test.java 2. sorának a második vonala lesz.

Szóval, honnan jött ez? Ebben az esetben nyilvánvaló, és természetesen, mit kell tennünk annak érdekében, hogy megoldjuk ezt. (Nem nulla érték hozzárendelése foo-hoz)

Rendben, próbálj ki egy kicsit ravasz példát. Ez logikai következtetést igényel.

Tehát most már 2 vonal van "online". Az első az erre a sorra:

És a második - erre a sorra:

Tehát, ha az első sorban nézzük, hogyan okozhat ez az NPE? Valójában kétféleképpen lehet:

  • Ha a sáv értéke nulla, akkor a bar [pozíció] hívja az NPE-t.
  • Ha a bar [pozíció] nulla, akkor a hossza () hívja az NPE-t.

Ezért meg kell tudnunk találni, hogy ezek közül melyik forgatókönyvek magyarázzák, mi történik. Kezdjük az első tanulmányozásával:

Honnan jön a bár? Ez a paraméter, amely a vizsgálati módszert hívja. és ha megnézzük, hogyan hívták a tesztet. láthatjuk, hogy a statikus változó foo-ból származik. És világosan látjuk, hogy inicializáltuk a nem-nulla értéket. Ez elég ahhoz, hogy feltételesen elutasítsuk ezt a magyarázatot. (Elméletileg valami mást is megváltoztathat nullra, de itt nem történik meg).

Mi a helyzet a második forgatókönyvvel? Nos, látjuk, hogy a pozíció 1. Ez azt jelenti, hogy a foo [1] nulla. Ez lehetséges?

Tényleg! És ez a probléma. Amikor inicializálunk így:

A String [] -ot két olyan elemhez osztjuk szét, amelyek inicializálva nulla értékűek. És akkor nem változtattuk meg a foo tartalmát. így a foo [1] továbbra is nulla lesz.

Egy null pointer kivétel akkor fordul elő, ha egy változó nullra mutat. Lásd a következő kódot:

A null pointer kivételt akkor dobjuk ki, amikor az alkalmazás megpróbál nullot használni abban az esetben, amikor egy objektum szükséges. Ezek a következők:

  1. Hívja az objektum null példányának módját.
  2. Az objektum null mezőjének elérése vagy módosítása.
  3. Figyelembe véve a null hosszúságát, mintha egy tömb lenne.
  4. A résidők elérése vagy módosítása null, mintha tömb lenne.
  5. A nullot úgy dobálják, mintha egy Throwable érték lenne.

Az alkalmazásoknak ebbe az osztályba tartozó példányokat kell lerázniuk a null objektum másik illegális használatára való utalásra.

A NULL mutató az, ami a semmibe mutat. Amikor a mutatót p. azt mondja: "adja meg az adatokat a" p "-ben tárolt helyen. Ha p egy nulla mutató, akkor a p. Sehol se mondja, azt mondja: "adja meg az adatokat a" Sehol "helyen. Nyilvánvaló, hogy ezt nem teheti meg, ezért NULL mutató kivétel.

Általánosságban ez azért van, mert valamit nem sikerült inicializálni.

Számos magyarázat létezik már arra, hogy elmagyarázza, hogyan történik ez, és hogyan kell ezt megoldani, de a NullPointerException kizárására vonatkozó ajánlásokat is követnie kell.

  1. Használjon végleges módosítót a jó inicializálás érdekében.
  2. Kerülje a null visszatérését a módszerekben, például ha üres gyűjteményeket visz vissza.
  3. Használjon jelöléseket @NotNull és @Nullable
  4. Gyors ütemezés és kimutatások használata a null objektumok terjedésének elkerülése érdekében az egész alkalmazásban, ha nem kell nulla.
  5. Először használjon értékeket egy ismert objektummal: if ("knownObject" .equals (unknownObject)
  6. A valueOf () értékét aString () fölé helyezi.
  7. Használjon null safe methods StringUtils.isEmpty (null).

A Java-ban minden dolog egy osztály formájában van.

Ha bármilyen tárgyat akarsz használni, akkor két fázisod van

Ugyanaz az Array koncepció

  • Nyilatkozat: i. Pont [] = új tétel [5];
  • Inicializálás: i [0] = új elem ();

Ha nem adja meg a NullpointerException részt, a NullpointerException megjelenik.

Az egy null mutatóval rendelkező kivétel azt jelzi, hogy az objektumot inicializálása nélkül használja.

Például az alábbiakban a hallgatók osztályát fogjuk használni a kódunkban.

Az alábbi kód megadja a null pointer kivételt.

Mivel az Obj_Student programot használja, elfelejtette inicializálni, ahogy az az alábbi ábrán látható.

Az objektum a VM memóriaterületben él, és az egyetlen hozzáférés erre a hivatkozások használatával. Vessük a következő példát:

A NullPointerException egy másik előfordulása akkor is előfordul, amikor az objektumok tömbjét deklarálják, majd azonnal megpróbálja megnézni a benne lévő elemeket.

Ezt az NPE-t el lehet kerülni, ha az összehasonlítási sorrendet törlik; Vagyis a .equals egy garantált nonzero objektumot használja.

A tömbben lévő összes elemet egy közös közös értékkel kezdjük; Minden objektumtípus esetén minden elem nulla.

Inicializálni kell az elemeket a tömbben, mielőtt hozzájuk férne, vagy feloldja őket.