Yanıtlar:
Bir referans değişkeni (yani bir nesne) bildirdiğinizde, gerçekten bir nesneye işaretçi oluşturursunuz. İlkel tipte bir değişken bildirdiğinizde aşağıdaki kodu göz önünde bulundurun int
:
int x;
x = 10;
Bu örnekte, değişken x
bir int
ve Java bunu 0
sizin için başlatacaktır . 10
İkinci satıra değerini atadığınızda, değeriniz 10
atıfta bulunulan bellek konumuna yazılır x
.
Ancak, bir başvuru türü bildirmeye çalıştığınızda , farklı bir şey olur. Aşağıdaki kodu alın:
Integer num;
num = new Integer(10);
İlk satır adlı bir değişken bildirir num
, ancak aslında henüz ilkel bir değer içermez. Bunun yerine, bir işaretçi içerir (çünkü tür Integer
bir referans türüdür). Neye işaret edeceğinizi henüz söylemediğiniz için Java bunu null
" hiçbir şeye işaret etmiyorum " anlamına gelir .
İkinci satırda, new
anahtar kelime türünde bir nesneyi başlatmak (veya oluşturmak) için kullanılır Integer
ve işaretçi değişkeni num
o Integer
nesneye atanır .
NullPointerException
Bir değişkeni bildirir ancak değişkenin (denilen içeriğini kullanmayı denemeden önce değişkene bir nesne ve ata yaratmadı oluşur başvurusu kaldırma ). Yani aslında var olmayan bir şeye işaret ediyorsunuz.
Dereferencing genellikle .
bir yönteme veya alana erişmek için kullanılırken veya [
bir dizini dizine eklemek için kullanılır .
num
Nesneyi oluşturmadan ÖNCE kayıttan ayrılmaya çalışırsanız, bir NullPointerException
. En önemsiz durumlarda, derleyici sorunu yakalar ve bunu " num may not have been initialized
," size bildirir , ancak bazen doğrudan nesneyi oluşturmayan bir kod yazabilirsiniz.
Örneğin, aşağıdaki gibi bir yönteminiz olabilir:
public void doSomething(SomeObject obj) {
//do something to obj
}
Bu durumda, nesneyi oluşturmazsınız obj
, bunun yerine doSomething()
yöntem çağrılmadan önce oluşturulduğunu varsayarsınız . Not, yöntemi şöyle çağırmak mümkündür:
doSomething(null);
Bu durumda, obj
bir null
. Yöntemin, iletilen nesneye bir şey yapması amaçlanıyorsa, NullPointerException
bir programcı hatası olduğu ve programcının hata ayıklama amacıyla bu bilgilere ihtiyacı olacağı için atmak uygundur . Lütfen istisna iletisine nesne değişkeninin adını ekleyin.
Objects.requireNonNull(a, "a");
Alternatif olarak, yöntemin amacının yalnızca iletilen nesnede çalışması olmadığı ve bu nedenle bir boş parametrenin kabul edilebilir olduğu durumlar olabilir. Bu durumda, null parametresini kontrol etmeniz ve farklı davranmanız gerekir. Bunu belgelerde de açıklamalısınız. Örneğin, doSomething()
şu şekilde yazılabilir:
/**
* @param obj An optional foo for ____. May be null, in which case
* the result will be ____.
*/
public void doSomething(SomeObject obj) {
if(obj == null) {
//do something
} else {
//do something else
}
}
Son olarak, Yığın İzi'ni kullanarak kural dışı durumu ve nedeni belirleme
İstisnanın programın erken sonlandırılmasına neden olmasını önlemek için nedeni belirlemek için hangi yöntemler / araçlar kullanılabilir?
Findbugs ile Sonar NPE tespit edebilir. Sonar, dinamik olarak JVM'nin neden olduğu boş gösterici istisnalarını yakalayabilir mi
int a=b
b ise bir NPE atabilir Integer
. Bunun hata ayıklamak için kafa karıştırıcı olduğu durumlar vardır.
NullPointerException
Kodunuzdaki sorunlardan kaçınmanın ek bir yolu kullanmak @Nullable
ve @NotNull
ek açıklamaları kullanmaktır . Aşağıdaki cevap bu konuda daha fazla bilgi içerir. Bu yanıt özellikle IntelliJ IDE ile ilgili olsa da, yorumlardan da anlaşılacağı gibi diğer araçlar için de geçerlidir. (BTW Bu yanıtı doğrudan düzenlememe izin verilmiyor, belki yazar ekleyebilir mi?)
NullPointerException
s, bir nesneye başvuruyormuş gibi bellekte (null) hiçbir yere işaret etmeyen bir başvuru kullanmaya çalıştığınızda oluşan özel durumlardır. Bir null referanstaki bir yöntemi çağırmak veya null referansın bir alanına erişmeye çalışmak a NullPointerException
. Bunlar en yaygın olanlarıdır, ancak diğer yollar NullPointerException
javadoc sayfasında listelenmiştir .
Muhtemelen en hızlı örnek kodu ben bir göstermek için gelip NullPointerException
olabilir:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
İçerideki ilk satırda main
, Object
referansı açıkça obj
eşit olarak ayarlıyorum null
. Bu bir referansım olduğu anlamına geliyor, ancak herhangi bir nesneye işaret etmiyor. Bundan sonra, başvuruyu, bir yöntemi çağırarak bir nesneye işaret ediyormuş gibi ele almaya çalışıyorum. Bunun NullPointerException
nedeni, başvurunun işaret ettiği konumda yürütülecek kod olmamasıdır.
(Bu bir tekniktir, ancak bahsettiğini düşünüyorum: null değerine işaret eden bir başvuru, geçersiz bir bellek konumuna işaret eden bir C işaretçisiyle aynı değildir. Null işaretçisi tam anlamıyla hiçbir yere işaret etmiyor , geçersiz olan bir yere işaret ediyor.)
null
, kullanmadan önce böyle . Yerel değişkenlerde, derleyici bu hatayı yakalar, ancak bu durumda yakalamaz. Belki bu cevabınıza faydalı bir katkı yapar mı?
Başlamak için iyi bir yer JavaDocs . Bunları kapsamaktadır:
Bir uygulama, bir nesnenin gerekli olduğu bir durumda null kullanmaya çalıştığında atılır. Bunlar:
- Boş bir nesnenin örnek yöntemini çağırma.
- Boş bir nesnenin alanına erişme veya bu nesneyi değiştirme.
- Null uzunluğunu bir diziymiş gibi almak.
- Null yuvalarına bir diziymiş gibi erişme veya bunları değiştirme.
- Atılabilir bir değermiş gibi boş atıyor.
Uygulamalar null nesnesinin diğer yasadışı kullanımlarını belirtmek için bu sınıfın örneklerini atmalıdır.
Ayrıca bir null başvuru kullanmaya kalkarsanız Eğer durum synchronized
da, bu istisna durumu, JLS başına :
SynchronizedStatement: synchronized ( Expression ) Block
- Aksi takdirde, İfadenin değeri null olursa a
NullPointerException
atılır.
Yani bir tane var NullPointerException
. Nasıl tamir edersin? A atarak basit bir örnek verelim NullPointerException
:
public class Printer {
private String name;
public void setName(String name) {
this.name = name;
}
public void print() {
printString(name);
}
private void printString(String s) {
System.out.println(s + " (" + s.length() + ")");
}
public static void main(String[] args) {
Printer printer = new Printer();
printer.print();
}
}
Boş değerleri belirleme
İlk adım, istisnaya hangi değerlerin tam olarak neden olduğunu tanımlamaktır . Bunun için hata ayıklama yapmamız gerekiyor. Bir yığın izini okumayı öğrenmek önemlidir . Bu size istisnanın nereye atıldığını gösterecektir:
Exception in thread "main" java.lang.NullPointerException
at Printer.printString(Printer.java:13)
at Printer.print(Printer.java:9)
at Printer.main(Printer.java:19)
Burada, istisnanın 13. hatta ( printString
yöntemde) atıldığını görüyoruz . Satıra bakın ve günlük kaydı ifadeleri ekleyerek veya bir hata ayıklayıcı kullanarak hangi değerlerin boş olduğunu kontrol edin . Bunun s
null length
olduğunu öğrendik ve üzerine yöntemin çağrılması istisnayı atar. s.length()
Yöntemden kaldırıldığında programın istisnayı atmayı bıraktığını görebiliriz.
Bu değerlerin nereden geldiğini izleyin
Sonra bu değerin nereden geldiğini kontrol edin. Yöntemin arayanları takip ederek, biz görüyoruz s
İle geçirilir printString(name)
içinde print()
yöntemle ve this.name
boş.
Bu değerlerin nerede ayarlanacağını izleyin
Nerede this.name
ayarlanır? İn setName(String)
yöntemi. Daha fazla hata ayıklama ile, bu yöntemin hiç çağrılmadığını görebiliriz. Yöntem denilen ise, mutlaka kontrol edin emri bu yöntemler dendiğini ve set yöntemi çağrılmaz sonra baskı yöntemiyle.
Bu bize bir çözüm sunmak için yeterlidir: printer.setName()
aramadan önce bir çağrı ekleyin printer.print()
.
Değişkenin varsayılan bir değerisetName
olabilir (ve null değerine ayarlanmasını engelleyebilirsiniz):
private String name = "";
Her iki print
ya da printString
yöntem olabilir boş kontrol , örneğin:
printString((name == null) ? "" : name);
Veya sınıfı name
her zaman boş olmayan bir değere sahip olacak şekilde tasarlayabilirsiniz :
public class Printer {
private final String name;
public Printer(String name) {
this.name = Objects.requireNonNull(name);
}
public void print() {
printString(name);
}
private void printString(String s) {
System.out.println(s + " (" + s.length() + ")");
}
public static void main(String[] args) {
Printer printer = new Printer("123");
printer.print();
}
}
Ayrıca bakınız:
Sorunu ayıklamaya çalıştıysanız ve hala bir çözümünüz yoksa, daha fazla yardım için bir soru gönderebilirsiniz, ancak şimdiye kadar denediklerinizi eklediğinizden emin olun. En azından, soruya yığın izini ekleyin ve koddaki önemli satır numaralarını işaretleyin . Ayrıca, önce kodu basitleştirmeyi deneyin (bkz. SSCCE ).
NullPointerException
(NPE) nin nedeni nedir ?Bildiğiniz gerektiği gibi, Java tipleri ayrılır ilkel türleri ( boolean
, int
vs.) ve referans türleri . Java'daki başvuru türleri, null
"nesne yok" demenin Java yöntemi olan özel değeri kullanmanızı sağlar .
NullPointerException
Programınız null
gerçek bir referansmış gibi a kullanmaya çalıştığında çalışma zamanında A atılır . Örneğin, bunu yazarsanız:
public class Test {
public static void main(String[] args) {
String foo = null;
int length = foo.length(); // HERE
}
}
"HERE" etiketli ifade length()
yöntemi bir null
başvuru üzerinde çalıştırmayı dener ve bu a'yı atar NullPointerException
.
A ile null
sonuçlanacak bir değeri kullanmanın birçok yolu vardır NullPointerException
. Aslında, o tek şey olabilir bir ilgisi null
bir NPE neden olmadan şunlardır:
==
veya !=
işleçlerini kullanarak sınayın veya instanceof
.Yukarıdaki programı derlediğimi ve çalıştırdığımı varsayalım:
$ javac Test.java
$ java Test
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:4)
$
İlk gözlem: derleme başarılı! Programdaki sorun bir derleme hatası DEĞİLDİR. Bir çalışma zamanı hatasıdır. (Bazı IDE'ler programınızın her zaman bir istisna atacağı konusunda uyarabilir ... ancak standart javac
derleyici bunu yapmaz.)
İkinci gözlem: programı çalıştırdığımda, iki satır "gobbledy-gook" çıktısı verir. YANLIŞ!! Bu gobbledy-gook değil. Bu bir yığın izidir ... ve dikkatlice okumak için zaman ayırırsanız kodunuzdaki hatayı izlemenize yardımcı olacak hayati bilgiler sağlar .
Öyleyse ne dediğine bakalım:
Exception in thread "main" java.lang.NullPointerException
Yığın izinin ilk satırı size birkaç şey anlatır:
java.lang.NullPointerException
.NullPointerException
bu konuda alışılmadık bir durumdur, çünkü nadiren bir hata mesajı vardır.İkinci çizgi, NPE tanısında en önemli olanıdır.
at Test.main(Test.java:4)
Bu bize birkaç şey söyler:
main
yönteminde olduğumuzu söylüyor Test
.Yukarıdaki dosyadaki satırları sayarsanız, 4. satır "BURAYA" yorumuyla etiketlediğim satırdır.
Daha karmaşık bir örnekte, NPE yığın izlemesinde çok sayıda satır olacağını unutmayın. Ancak ikinci satırın (ilk "at" satırının) size NPE'nin nereye atıldığını söyleyeceğinden emin olabilirsiniz 1 .
Kısacası, yığın izleme bize programın hangi ifadesinin NPE'yi attığını açık bir şekilde söyleyecektir.
1 - Pek doğru değil. İç içe istisnalar denen şeyler var ...
Zor kısmı bu. Kısa cevap, yığın izlemesi, kaynak kodu ve ilgili API dokümantasyonu tarafından sağlanan kanıtlara mantıksal çıkarım uygulamaktır.
Önce basit örnekle (yukarıda) açıklayalım. Yığın izinin bize NPE'nin nerede olduğunu söylediği çizgiye bakarak başlarız:
int length = foo.length(); // HERE
Bu nasıl bir NPE fırlatabilir?
Aslında, tek bir yol vardır: bu sadece foo
değere sahipse olabilir null
. Daha sonra length()
yöntemi çalıştırmaya çalışıyoruz null
ve ... BANG!
Ama (dediğini duyuyorum) ya NPE length()
yöntem çağrısının içine atılırsa ?
Eğer bu olsaydı, yığın izi farklı görünürdü. İlk "at" satırı, istisnanın java.lang.String
sınıftaki bir satıra atıldığını ve 4. satırının Test.java
ikinci "at" satırı olacağını söyler .
Peki bu null
nereden geldi? Bu durumda, açıktır ve düzeltmek için ne yapmamız gerektiği açıktır. (Konumuna boş olmayan bir değer atayın foo
.)
Tamam, biraz daha zor bir örnek deneyelim. Bu biraz mantıksal kesinti gerektirecektir .
public class Test {
private static String[] foo = new String[2];
private static int test(String[] bar, int pos) {
return bar[pos].length();
}
public static void main(String[] args) {
int length = test(foo, 1);
}
}
$ javac Test.java
$ java Test
Exception in thread "main" java.lang.NullPointerException
at Test.test(Test.java:6)
at Test.main(Test.java:10)
$
Şimdi iki tane "satır" çizgimiz var. İlki bu çizgi için:
return args[pos].length();
ve ikincisi bu çizgi içindir:
int length = test(foo, 1);
İlk satıra bakıldığında, bu nasıl bir NPE fırlatabilir? İki yol vardır:
bar
, null
o bar[pos]
zaman bir NPE atar.bar[pos]
edilir null
daha sonra arayarak length()
üzerine bir NPE atar.Sonra, bu senaryolardan hangisinin gerçekte neler olduğunu açıkladığını bulmamız gerekiyor. İlkini keşfederek başlayacağız:
Nereden bar
geliyor? Bu, test
yöntem çağrısının bir parametresidir ve nasıl test
çağrıldığına bakarsak, foo
statik değişkenden geldiğini görebiliriz . Ayrıca, foo
null olmayan bir değere başlattığımızı açıkça görebiliriz . Bu açıklamayı geçici olarak reddetmek yeterlidir. (Teorik olarak, başka bir şey olabilir değiştirmek foo
için null
... ama bu burada olmuyor.)
İkinci senaryomuz ne olacak? Eh, biz görebilirsiniz pos
olduğunu 1
, bu yollarla böylece foo[1]
olmalıdır null
. Mümkün mü?
Gerçekten öyle! ve problem bu. Bu şekilde başlattığımızda:
private static String[] foo = new String[2];
Biz tahsis String[]
iki unsurları ile başlatılırnull
. Bundan sonra, içeriğini değiştirmedik foo
... öyle foo[1]
olmayacak null
.
Sanki bir nesneye erişmeye çalışıyorsun null
. Aşağıdaki örneği düşünün:
TypeA objA;
Şu anda bu nesneyi yeni beyan ettiniz, ancak başlatılmadınız veya somutlaştırılmadınız . Ve içindeki herhangi bir mülke veya yönteme erişmeye çalıştığınızda NullPointerException
, mantıklı olacaktır.
Aşağıdaki örneğe de bakın:
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
Bir uygulama bir nesnenin gerekli olduğu bir durumda null kullanmaya çalıştığında bir boş işaretçi istisnası atılır. Bunlar:
null
nesnenin örnek yöntemini çağırma .null
nesnenin alanına erişme veya alanın üzerinde değişiklik yapma .null
Bir dizi gibi uzunluğunu almak .null
Sanki bir diziymiş gibi yuvalarına erişme veya bunları değiştirme .null
bir Atılabil değer sanki.Uygulamalar, null
nesnenin diğer yasadışı kullanımlarını belirtmek için bu sınıfın örneklerini atmalıdır.
Referans: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html
null
bir hedefi olarak synchronized
bloğunun, 2) kullanılarak null
bir hedefi olarak switch
ve unboxing null
.
Bir null
işaretçi hiçbir için bir o puandır. Bir işaretçi çözümlemesi yaparken p
, sen p "saklanan yerde bana veri sağlamak 'demek'. Ne zaman p
bir olan null
işaretçi, depolanan yer p
almaktadır nowhere
diyorsunuz '' 'hiçbir' yerde bana veriler gösterir. Açıkçası, bunu yapamaz, bu yüzden a atar null pointer exception
.
Genel olarak, bunun nedeni bir şeyin doğru şekilde başlatılmamış olmasıdır.
NULL
dilinde yazılmıştır null
. Ve bu büyük / küçük harfe duyarlı bir şey.
Nasıl olduğunu ve nasıl düzeltileceğini açıklamak için birçok açıklama zaten var, ancak önlemek için en iyi uygulamaları da takip etmelisiniz.NullPointerException
s'yi .
Ayrıca bakınız: En iyi uygulamaların iyi bir listesi
Çok önemli bir şekilde, final
değiştiriciyi iyi bir şekilde kullanacağımı ekledim.
Java'da uygulanabilir olduğunda "son" değiştiriciyi kullanma
Özet:
final
İyi başlatmayı zorunlu kılmak değiştiriciyi .@NotNull
ve@Nullable
if("knownObject".equals(unknownObject)
valueOf()
üzerindetoString()
.StringUtils
yöntemler kullanınStringUtils.isEmpty(null)
.@Nullable
. Yukarıda listelendiği gibi) dayalı otomatik iptal analizleri sunduğunu ve potansiyel hatalar hakkında uyarıldığını belirtmek gerekir . Mevcut kod yapısına dayanarak bu tür ek açıklamaları (örn. IntelliJ bunu yapabilir) çıkarmak ve oluşturmak da mümkündür.
if (obj==null)
. Null ise, bu durumda da işlemek için kod yazmalısınız.
Java'da her şey (ilkel türler hariç) bir sınıf şeklindedir.
Herhangi bir nesneyi kullanmak istiyorsanız iki aşama vardır:
Misal:
Object object;
object = new Object();
Dizi konsepti için aynı:
Item item[] = new Item[5];
item[0] = new Item();
Başlatma bölümünü vermiyorsanız, NullPointerException
ortaya çıkar.
Boş işaretçi istisnası, bir nesneyi başlatmadan kullandığınızın bir göstergesidir.
Örneğin, onu kodumuzda kullanacak bir öğrenci sınıfı aşağıdadır.
public class Student {
private int id;
public int getId() {
return this.id;
}
public setId(int newId) {
this.id = newId;
}
}
Aşağıdaki kod size bir boş gösterici istisnası verir.
public class School {
Student student;
public School() {
try {
student.getId();
}
catch(Exception e) {
System.out.println("Null pointer exception");
}
}
}
Çünkü kullanıyorsunuz student
, ancak aşağıda gösterilen doğru kodda olduğu gibi başlatmayı unuttunuz:
public class School {
Student student;
public School() {
try {
student = new Student();
student.setId(12);
student.getId();
}
catch(Exception e) {
System.out.println("Null pointer exception");
}
}
}
In Java Gümrüğe bütün değişkenler nesneler (veya ilkel) için "referanslar" ve aslında kendileri nesnelerdir.
Bir nesne yöntemini yürütmeye çalıştığınızda başvuru, yaşayan nesneden bu yöntemi yürütmesini ister. Ancak, başvuru NULL değerine başvuruyorsa (hiçbir şey, sıfır, geçersiz, nada), yöntemin yürütülmesinin bir yolu yoktur. Sonra çalışma zamanı bir NullPointerException atarak bunu size bildirir.
Referansınız "null" u işaret ediyor, dolayısıyla "Null -> Pointer".
Nesne VM bellek alanında yaşıyor ve ona erişmenin tek yolu this
referanslar kullanmak . Bu örneği ele alalım:
public class Some {
private int id;
public int getId(){
return this.id;
}
public setId( int newId ) {
this.id = newId;
}
}
Ve kodunuzdaki başka bir yerde:
Some reference = new Some(); // Point to a new object of type Some()
Some otherReference = null; // Initiallly this points to NULL
reference.setId( 1 ); // Execute setId method, now private var id is 1
System.out.println( reference.getId() ); // Prints 1 to the console
otherReference = reference // Now they both point to the only object.
reference = null; // "reference" now point to null.
// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );
// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...
Bu, bilinmesi gereken önemli bir şeydir - bir nesneye daha fazla referans olmadığında (yukarıdaki örnekte ne zaman reference
ve otherReference
her ikisi de null değerine işaret ettiğinde ), nesne "ulaşılamaz" dır. Onunla çalışmanın hiçbir yolu yoktur, bu nedenle bu nesne çöp toplanmaya hazırdır ve bir noktada VM, bu nesne tarafından kullanılan belleği serbest bırakır ve başka bir nesne tahsis eder.
Bir NullPointerException
nesne nesnesinin bir dizisini bildirdikten sonra derhal içindeki öğelerin kayıttan çıkarılması çalıştığında başka bir oluşum oluşur.
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Karşılaştırma sırası tersine çevrilirse bu özel NPE'den kaçınılabilir; yani, kullanın.equals
garantili boş olmayan bir nesne üzerinde .
Bir dizinin içindeki tüm öğeler ortak başlangıç değerlerine sıfırlanır ; herhangi bir nesne dizisi türü için bu, tüm öğelerinnull
.
Sen gerekir dizideki öğeleri başlatmak önce erişen veya bunları dereferencing.
String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Optional
null değerini döndürmekti. Anahtar kelime iyi. Buna karşı nasıl korunacağını bilmek çok önemlidir. Bu, onun ortak bir oluşumunu ve hafifletmenin yollarını sunar.