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 xbir intve Java bunu 0sizin için başlatacaktır . 10İkinci satıra değerini atadığınızda, değeriniz 10atı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 Integerbir 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, newanahtar kelime türünde bir nesneyi başlatmak (veya oluşturmak) için kullanılır Integerve işaretçi değişkeni numo Integernesneye atanır .
NullPointerExceptionBir 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 .
numNesneyi 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, objbir null. Yöntemin, iletilen nesneye bir şey yapması amaçlanıyorsa, NullPointerExceptionbir 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=bb ise bir NPE atabilir Integer. Bunun hata ayıklamak için kafa karıştırıcı olduğu durumlar vardır.
NullPointerExceptionKodunuzdaki sorunlardan kaçınmanın ek bir yolu kullanmak @Nullableve @NotNullek 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?)
NullPointerExceptions, 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 NullPointerExceptionjavadoc sayfasında listelenmiştir .
Muhtemelen en hızlı örnek kodu ben bir göstermek için gelip NullPointerExceptionolabilir:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
İçerideki ilk satırda main, Objectreferansı açıkça objeş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 NullPointerExceptionnedeni, 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 synchronizedda, bu istisna durumu, JLS başına :
SynchronizedStatement: synchronized ( Expression ) Block
- Aksi takdirde, İfadenin değeri null olursa a
NullPointerExceptionatı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 ( printStringyö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 snull lengtholduğ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.nameboş.
Bu değerlerin nerede ayarlanacağını izleyin
Nerede this.nameayarlanı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 printya da printStringyö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, intvs.) 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 .
NullPointerExceptionProgramınız nullgerç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 nullbaşvuru üzerinde çalıştırmayı dener ve bu a'yı atar NullPointerException.
A ile nullsonuçlanacak bir değeri kullanmanın birçok yolu vardır NullPointerException. Aslında, o tek şey olabilir bir ilgisi nullbir 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 javacderleyici 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.NullPointerExceptionbu 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:
mainyö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 foodeğere sahipse olabilir null. Daha sonra length()yöntemi çalıştırmaya çalışıyoruz nullve ... 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.Stringsınıftaki bir satıra atıldığını ve 4. satırının Test.javaikinci "at" satırı olacağını söyler .
Peki bu nullnereden 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, nullo bar[pos]zaman bir NPE atar.bar[pos]edilir nulldaha 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 bargeliyor? Bu, testyöntem çağrısının bir parametresidir ve nasıl testçağrıldığına bakarsak, foostatik değişkenden geldiğini görebiliriz . Ayrıca, foonull 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 posolduğ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:
nullnesnenin örnek yöntemini çağırma .nullnesnenin alanına erişme veya alanın üzerinde değişiklik yapma .nullBir dizi gibi uzunluğunu almak .nullSanki bir diziymiş gibi yuvalarına erişme veya bunları değiştirme .nullbir Atılabil değer sanki.Uygulamalar, nullnesnenin 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
nullbir hedefi olarak synchronizedbloğunun, 2) kullanılarak nullbir hedefi olarak switchve unboxing null.
Bir nulliş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 pbir olan nullişaretçi, depolanan yer palmaktadır nowherediyorsunuz '' '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.
NULLdilinde 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, finaldeğ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 .@NotNullve@Nullableif("knownObject".equals(unknownObject)valueOf()üzerindetoString() .StringUtilsyö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, NullPointerExceptionortaya çı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 thisreferanslar 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 referenceve otherReferenceher 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 NullPointerExceptionnesne 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));
}
Optionalnull 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.