admin

Uy tín: 0

Các thẻ đã đăng ký:

Câu hỏi được trả lời bởi người dùng.

Khi bạn khai báo một biến tham chiếu (tức là một đối tượng), bạn thực sự đang tạo một con trỏ đến một đối tượng. Hãy xem xét đoạn mã sau nơi bạn khai báo một biến kiểu nguyên thủy int:

int x;
x = 10;

Trong ví dụ này, biến xlà một intvà Java sẽ khởi tạo nó 0cho bạn. Khi bạn gán cho nó giá trị 10trên dòng thứ hai, giá trị của bạn 10sẽ được ghi vào vị trí bộ nhớ được tham chiếu đến x.

Tuy nhiên, khi bạn cố gắng khai báo một kiểu tham chiếu , điều gì đó khác sẽ xảy ra. Lấy đoạn mã sau:

Integer num;
num = new Integer(10);

Dòng đầu tiên khai báo một biến có tên num, nhưng nó thực sự chưa chứa giá trị nguyên thủy. Thay vào đó, nó chứa một con trỏ (vì kiểu là Integerkiểu tham chiếu). Vì bạn chưa nói nên trỏ tới cái gì, nên Java đặt nó thành null, có nghĩa là " Tôi đang trỏ tới không có gì ".

Trong dòng thứ hai, newtừ khóa được sử dụng để khởi tạo (hoặc tạo) một đối tượng kiểu Integer, và biến con trỏ numđược gán cho Integerđối tượng đó .

Điều NullPointerExceptionnày xảy ra khi bạn khai báo một biến nhưng không tạo một đối tượng và gán nó cho biến trước khi cố gắng sử dụng nội dung của biến (được gọi là dereferencing ). Vì vậy, bạn đang chỉ vào một cái gì đó không thực sự tồn tại.

Tham chiếu thường xảy ra khi sử dụng .để truy cập một phương thức hoặc trường hoặc sử dụng [để lập chỉ mục một mảng.

Nếu bạn cố gắng bỏ tham khảo numTRƯỚC khi tạo đối tượng, bạn nhận được a NullPointerException. Trong những trường hợp nhỏ nhất, trình biên dịch sẽ nắm bắt được sự cố và cho bạn biết rằng " num may not have been initialized," nhưng đôi khi bạn có thể viết mã không trực tiếp tạo đối tượng.

Ví dụ, bạn có thể có một phương thức như sau:

public void doSomething(SomeObject obj) {
   //do something to obj
}

Trong trường hợp đó, bạn không tạo đối tượng obj, mà giả sử rằng nó được tạo trước khi doSomething()phương thức được gọi. Lưu ý, có thể gọi phương thức như sau:

doSomething(null);

Trong trường hợp đó, objlà null. Nếu phương thức được dự định thực hiện một điều gì đó với đối tượng được truyền vào, thì sẽ thích hợp để ném NullPointerExceptionvì đó là lỗi của lập trình viên và lập trình viên sẽ cần thông tin đó cho mục đích gỡ lỗi. Vui lòng bao gồm tên của biến đối tượng trong thông báo ngoại lệ, như

Objects.requireNonNull(a, "a");

Ngoài ra, có thể có những trường hợp mục đích của phương thức không phải chỉ hoạt động trên đối tượng được truyền vào, và do đó tham số null có thể được chấp nhận. Trong trường hợp này, bạn cần kiểm tra tham số null và hoạt động khác. Bạn cũng nên giải thích điều này trong tài liệu. Ví dụ, doSomething()có thể được viết là:

/**
  * @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
    }
}

Cuối cùng, Cách xác định nguyên nhân và ngoại lệ bằng cách sử dụng Stack Trace

Những phương pháp / công cụ nào có thể được sử dụng để xác định nguyên nhân để bạn ngăn ngoại lệ khiến chương trình kết thúc sớm?

Sonar với tìm lỗi có thể phát hiện NPE. Sonar có thể bắt các ngoại lệ con trỏ rỗng do JVM Dynamatic gây ra không

Bây giờ Java 14 đã thêm một tính năng ngôn ngữ mới để chỉ ra nguyên nhân gốc rễ của NullPointerException. Tính năng ngôn ngữ này là một phần của JVM thương mại SAP từ năm 2006. Sau đây là 2 phút đọc để hiểu tính năng ngôn ngữ tuyệt vời này.

https://jfeatures.com/blog/NullPointerException

Trong java 14 sau đây là mẫu thông báo ngoại lệ NullPointerException:

trong luồng "main" java.lang.NullPointerException: Không thể gọi "java.util.List.size ()" vì "danh sách" là null

16 ngày 3 giờ

NullPointerExceptions là những ngoại lệ xảy ra khi bạn cố gắng sử dụng một tham chiếu trỏ đến không có vị trí nào trong bộ nhớ (null) như thể nó đang tham chiếu đến một đối tượng. Việc gọi một phương thức trên một tham chiếu rỗng hoặc cố gắng truy cập vào một trường của một tham chiếu rỗng sẽ kích hoạt một NullPointerException. Đây là những cách phổ biến nhất, nhưng những cách khác được liệt kê trên NullPointerExceptiontrang javadoc.

Có lẽ đoạn mã ví dụ nhanh nhất mà tôi có thể đưa ra để minh họa cho một mã NullPointerExceptionsẽ là:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

Trên dòng đầu tiên bên trong main, tôi rõ ràng đặt Objecttham chiếu objbằng null. Điều này có nghĩa là tôi có một tham chiếu, nhưng nó không trỏ đến bất kỳ đối tượng nào. Sau đó, tôi cố gắng coi tham chiếu như thể nó trỏ đến một đối tượng bằng cách gọi một phương thức trên đó. Điều này dẫn đến một NullPointerExceptionvì không có mã nào để thực thi ở vị trí mà tham chiếu đang trỏ đến.

(Đây là một tính kỹ thuật, nhưng tôi nghĩ nó cần đề cập đến: Một tham chiếu trỏ đến null không giống như một con trỏ C trỏ đến một vị trí bộ nhớ không hợp lệ. Một con trỏ null nghĩa là không trỏ đến bất kỳ đâu , điều này khác một cách tinh tế hơn trỏ đến một vị trí không hợp lệ.)


chia sẻ  biên tập  theo 

16 ngày 3 giờ

NullPointerException là gì?

Một nơi tốt để bắt đầu là JavaDocs . Họ có điều này được bảo hiểm:

Bị ném khi ứng dụng cố gắng sử dụng null trong trường hợp yêu cầu một đối tượng. Bao gồm các:

  • Gọi phương thức thể hiện của một đối tượng null.
  • Truy cập hoặc sửa đổi trường của một đối tượng null.
  • Lấy độ dài của null như thể nó là một mảng.
  • Truy cập hoặc sửa đổi các vị trí rỗng như thể nó là một mảng.
  • Ném null như thể nó là một giá trị Có thể ném.

Các ứng dụng nên ném các thể hiện của lớp này để chỉ ra các cách sử dụng bất hợp pháp khác của đối tượng null.

Cũng có trường hợp nếu bạn cố gắng sử dụng tham chiếu null synchronized, điều đó cũng sẽ ném ra ngoại lệ này, theo JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • Ngược lại, nếu giá trị của Biểu thức là rỗng, a NullPointerExceptionsẽ được ném ra.

Làm thế nào để tôi sửa chữa nó?

Vì vậy, bạn có một NullPointerException. Làm thế nào để bạn sửa chữa nó? Hãy lấy một ví dụ đơn giản ném một 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();
    }
}

Xác định các giá trị rỗng

Bước đầu tiên là xác định chính xác giá trị nào gây ra ngoại lệ . Đối với điều này, chúng tôi cần thực hiện một số gỡ lỗi. Điều quan trọng là phải học cách đọc một stacktrace . Điều này sẽ cho bạn thấy nơi ngoại lệ được đưa ra:

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)

Ở đây, chúng ta thấy rằng ngoại lệ được ném vào dòng 13 (trong printStringphương thức). Nhìn vào dòng và kiểm tra giá trị nào là rỗng bằng cách thêm các câu lệnh ghi nhật ký hoặc sử dụng trình gỡ lỗi . Chúng tôi phát hiện ra rằng đó slà null và gọi lengthphương thức trên đó sẽ ném ra ngoại lệ. Chúng ta có thể thấy rằng chương trình ngừng ném ngoại lệ khi s.length()bị xóa khỏi phương thức.

Theo dõi những giá trị này đến từ đâu

Tiếp theo hãy kiểm tra xem giá trị này đến từ đâu. Bằng cách theo dõi các trình gọi của phương thức, chúng ta thấy rằng nó sđược chuyển vào với printString(name)trong print()phương thức và this.namelà null.

Theo dõi nơi các giá trị này nên được đặt

Đặt ở đâu this.name? Trong setName(String)phương pháp. Với một số gỡ lỗi khác, chúng ta có thể thấy rằng phương thức này hoàn toàn không được gọi. Nếu phương thức được gọi, hãy đảm bảo kiểm tra thứ tự mà các phương thức này được gọi và phương thức set không được gọi sau phương thức in.

Điều này đủ để cung cấp cho chúng tôi một giải pháp: thêm một cuộc gọi đến printer.setName()trước khi gọi printer.print().

Các bản sửa lỗi khác

Biến có thể có giá trị mặc định (và setNamecó thể ngăn nó được đặt thành null):

private String name = "";

Hoặc phương thức printhoặc printStringcó thể kiểm tra null , ví dụ:

printString((name == null) ? "" : name);

Hoặc bạn có thể thiết kế lớp để name luôn có giá trị khác rỗng :

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();
    }
}

Xem thêm:

Tôi vẫn không thể tìm ra vấn đề

Nếu bạn đã cố gắng gỡ lỗi sự cố mà vẫn không có giải pháp, bạn có thể đăng câu hỏi để được trợ giúp thêm, nhưng hãy đảm bảo bao gồm những gì bạn đã thử cho đến nay. Ít nhất, hãy đưa dấu ngăn xếp vào câu hỏi và đánh dấu các số dòng quan trọng trong mã. Ngoài ra, hãy thử đơn giản hóa mã trước (xem SSCCE ).

16 ngày 3 giờ

507

Câu hỏi: Nguyên nhân nào gây ra a NullPointerException(NPE)?

Như bạn nên biết, các loại Java được chia thành các loại nguyên thủy ( booleanint, vv) và các loại tài liệu tham khảo . Các kiểu tham chiếu trong Java cho phép bạn sử dụng giá trị đặc biệt nulllà cách Java nói "không có đối tượng".

NullPointerExceptionđược ném vào thời gian chạy bất cứ khi nào chương trình của bạn cố gắng sử dụng a nullnhư thể nó là một tham chiếu thực. Ví dụ: nếu bạn viết điều này:

public class Test {
    public static void main(String[] args) {
        String foo = null;
        int length = foo.length();   // HERE
    }
}

câu lệnh có nhãn "HERE" sẽ cố gắng chạy length()phương thức trên một nulltham chiếu và điều này sẽ ném ra một NullPointerException.

Có nhiều cách mà bạn có thể sử dụng một nullgiá trị sẽ dẫn đến a NullPointerException. Trên thực tế, những điều duy nhất bạn có thể làm với a nullmà không gây ra NPE là:

  • gán nó cho một biến tham chiếu hoặc đọc nó từ một biến tham chiếu,
  • gán nó cho một phần tử mảng hoặc đọc nó từ một phần tử mảng (miễn là bản thân tham chiếu mảng không phải là null!),
  • chuyển nó dưới dạng một tham số hoặc trả về nó dưới dạng kết quả, hoặc
  • kiểm tra nó bằng cách sử dụng ==hoặc !=khai thác, hoặc instanceof.

Câu hỏi: Làm cách nào để đọc hệ thống xếp chồng NPE?

Giả sử rằng tôi biên dịch và chạy chương trình trên:

$ javac Test.java 
$ java Test
Exception in thread "main" java.lang.NullPointerException
    at Test.main(Test.java:4)
$

Quan sát đầu tiên: việc biên dịch thành công! Sự cố trong chương trình KHÔNG phải là lỗi biên dịch. Đó là một lỗi thời gian chạy . (Một số IDE có thể cảnh báo chương trình của bạn sẽ luôn đưa ra một ngoại lệ ... nhưng javactrình biên dịch tiêu chuẩn thì không.)

Quan sát thứ hai: khi tôi chạy chương trình, nó xuất ra hai dòng "gobbledy-gook". SAI LẦM!! Đó không phải là gobbledy-gook. Nó là một stacktrace ... và nó cung cấp thông tin quan trọng sẽ giúp bạn tìm ra lỗi trong mã của mình nếu bạn dành thời gian đọc kỹ.

Vì vậy, hãy xem nó nói gì:

Exception in thread "main" java.lang.NullPointerException

Dòng đầu tiên của dấu vết ngăn xếp cho bạn biết một số điều:

  • Nó cho bạn biết tên của chuỗi Java mà ngoại lệ được đưa ra. Đối với một chương trình đơn giản với một luồng (như chương trình này), nó sẽ là "chính". Tiếp tục nào ...
  • Nó cho bạn biết tên đầy đủ của ngoại lệ đã được ném; tức là java.lang.NullPointerException.
  • Nếu ngoại lệ có một thông báo lỗi liên quan, thông báo đó sẽ được xuất sau tên ngoại lệ. NullPointerExceptionlà không bình thường về mặt này, vì nó hiếm khi có thông báo lỗi.

Dòng thứ hai là dòng quan trọng nhất trong việc chẩn đoán NPE.

at Test.main(Test.java:4)

Điều này cho chúng ta biết một số điều:

  • "at Test.main" nói rằng chúng tôi đang ở trong mainphương pháp của Testlớp học.
  • "Test.java:4" cung cấp tên tệp nguồn của lớp và nó cho chúng ta biết rằng câu lệnh nơi điều này xảy ra nằm ở dòng 4 của tệp.

Nếu bạn đếm các dòng trong tệp trên, dòng 4 là dòng mà tôi đã gắn nhãn với nhận xét "TẠI ĐÂY".

Lưu ý rằng trong một ví dụ phức tạp hơn, sẽ có rất nhiều dòng trong dấu vết ngăn xếp NPE. Nhưng bạn có thể chắc chắn rằng dòng thứ hai (dòng đầu tiên "tại") sẽ cho bạn biết nơi mà NPE đã được ném 1 .

Tóm lại, dấu vết ngăn xếp sẽ cho chúng ta biết rõ ràng câu lệnh nào của chương trình đã ném NPE.

1 - Không hoàn toàn đúng. Có những thứ được gọi là ngoại lệ lồng nhau ...

Câu hỏi: Làm cách nào để theo dõi nguyên nhân của ngoại lệ NPE trong mã của tôi?

Đây là phần cứng. Câu trả lời ngắn gọn là áp dụng suy luận logic cho bằng chứng được cung cấp bởi dấu vết ngăn xếp, mã nguồn và tài liệu API liên quan.

Hãy minh họa bằng ví dụ đơn giản (ở trên) trước. Chúng ta bắt đầu bằng cách xem xét dòng mà dấu vết ngăn xếp đã cho chúng ta biết là nơi xảy ra NPE:

int length = foo.length(); // HERE

Làm thế nào mà có thể ném một NPE?

Trên thực tế, chỉ có một cách: nó chỉ có thể xảy ra nếu foocó giá trị null. Sau đó, chúng tôi cố gắng chạy length()phương thức trên nullvà ... BANG!

Nhưng (tôi nghe bạn nói) điều gì sẽ xảy ra nếu NPE được ném vào bên trong lệnh length()gọi phương thức?

Chà, nếu điều đó xảy ra, dấu vết ngăn xếp sẽ trông khác. Dòng "at" đầu tiên cho biết rằng ngoại lệ đã được ném vào một số dòng trong java.lang.Stringlớp và dòng 4 của Test.javasẽ là dòng thứ hai "at".

Vậy điều đó nullđến từ đâu? Trong trường hợp này, đó là điều hiển nhiên, và rõ ràng chúng ta cần phải làm gì để khắc phục. (Gán một giá trị không rỗng cho foo.)

OK, vậy hãy thử một ví dụ phức tạp hơn một chút. Điều này sẽ yêu cầu một số suy luận hợp lý .

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)
$ 

Vì vậy, bây giờ chúng ta có hai dòng "at". Cái đầu tiên dành cho dòng này:

return args[pos].length();

và cái thứ hai dành cho dòng này:

int length = test(foo, 1);

Nhìn vào dòng đầu tiên, làm thế nào mà có thể ném NPE? Có hai cách:

  • Nếu giá trị của barlà nullthì bar[pos]sẽ ném ra một NPE.
  • Nếu giá trị của bar[pos]được nullgọi length()thì nó sẽ ném ra một NPE.

Tiếp theo, chúng ta cần tìm ra kịch bản nào giải thích được điều gì đang thực sự xảy ra. Chúng ta sẽ bắt đầu bằng cách khám phá cái đầu tiên:

Từ đâu barđến? Nó là một tham số cho testlời gọi phương thức, và nếu chúng ta nhìn vào cách nó testđược gọi, chúng ta có thể thấy rằng nó đến từ foobiến static. Ngoài ra, chúng ta có thể thấy rõ ràng rằng chúng ta đã khởi tạo foothành một giá trị khác rỗng. Điều đó đủ để bác bỏ lời giải thích này. (Về lý thuyết, một cái gì đó khác có thể thay đổi foo thành null... nhưng điều đó không xảy ra ở đây.)

Vậy còn kịch bản thứ hai của chúng ta? Chà, chúng ta có thể thấy đó poslà 1, vì vậy điều đó có nghĩa là foo[1]phải như vậy null. Điều này có khả thi không?

Quả thực là như vậy! Và đó là vấn đề. Khi chúng tôi khởi tạo như thế này:

private static String[] foo = new String[2];

chúng tôi phân bổ a String[]với hai phần tử được khởi tạonull . Sau đó, chúng tôi đã không thay đổi nội dung của foo... như vậy foo[1]vẫn sẽ như vậy null.

16 ngày 3 giờ

362

Một ngoại lệ con trỏ null được ném ra khi một ứng dụng cố gắng sử dụng null trong trường hợp một đối tượng được yêu cầu. Bao gồm các:

  1. Gọi phương thức thể hiện của một nullđối tượng.
  2. Truy cập hoặc sửa đổi trường của một nullđối tượng.
  3. Lấy chiều dài nullnhư thể nó là một mảng.
  4. Truy cập hoặc sửa đổi các vị trí nullnhư thể nó là một mảng.
  5. Ném nullnhư thể đó là một giá trị Có thể ném .

Các ứng dụng nên ném các thể hiện của lớp này để chỉ ra các cách sử dụng bất hợp pháp khác của nullđối tượng.

16 ngày 3 giờ

Một ngoại lệ con trỏ null là một chỉ báo rằng bạn đang sử dụng một đối tượng mà không khởi tạo nó.

Ví dụ, dưới đây là một lớp học sinh sẽ sử dụng nó trong mã của chúng tôi.

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

Đoạn mã dưới đây cung cấp cho bạn một ngoại lệ con trỏ null.

public class School {

    Student student;

    public School() {
        try {
            student.getId();
        }
        catch(Exception e) {
            System.out.println("Null pointer exception");
        }
    }
}

Do bạn đang sử dụng studentmà quên khởi tạo nó như đúng đoạn code bên dưới:

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");
        }
    }
}

16 ngày 3 giờ

Trong Java, tất cả các biến mà bạn khai báo thực sự là "tham chiếu" đến các đối tượng (hoặc nguyên thủy) chứ không phải bản thân các đối tượng.

Khi bạn cố gắng thực thi một phương thức đối tượng, tham chiếu sẽ yêu cầu đối tượng sống thực thi phương thức đó. Nhưng nếu tham chiếu đang tham chiếu đến NULL (nothing, zero, void, nada) thì không có cách nào phương thức được thực thi. Sau đó, thời gian chạy cho bạn biết điều này bằng cách ném một NullPointerException.

Tham chiếu của bạn là "trỏ" đến null, do đó "Null -> Con trỏ".

Đối tượng sống trong không gian bộ nhớ VM và cách duy nhất để truy cập nó là sử dụng thistham chiếu. Lấy ví dụ sau:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

Và ở một nơi khác trong mã của bạn:

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...

Đây là một điều quan trọng cần biết - khi không còn tham chiếu nào đến một đối tượng (trong ví dụ trên khi referencevà otherReferencecả hai đều trỏ đến null) thì đối tượng đó là "không thể truy cập". Không có cách nào chúng ta có thể làm việc với nó, vì vậy đối tượng này đã sẵn sàng để được thu gom rác, và tại một thời điểm nào đó, máy ảo sẽ giải phóng bộ nhớ được sử dụng bởi đối tượng này và sẽ cấp phát một đối tượng khác.

16 ngày 3 giờ

Nâng cấp lên MVC 5.1 và bạn có thể sử dụng các thuộc tính HTML trong EditorFor:

@Html.EditorFor(m => m.variable, new { htmlAttributes = new { placeholder = "Your Placeholder Text" } })

http://www.asp.net/mvc/overview/releases/mvc51-release-notes

16 ngày 4 giờ

Your query executes one subquery for each document in the existing collection. Each subquery will require many HTTP roundtrips for setup, the actual querying and shutdown.

You can avoid subqueries with the following query. It loads all document _key's into RAM - but that should be no problem with your rather small collections.

LET ExistingCollection = (FOR existing IN c2 RETURN existing._key)
LET TempCollection = (FOR temp IN c1 RETURN temp._key)
RETURN MINUS(ExistingCollection, TempCollection)

16 ngày 6 giờ

Là sao hả admin 

16 ngày 6 giờ

Các thẻ đã đăng ký của người dùng: admin

Tags
×