Không có ngoại lệ trong khi nhập kiểu với null trong java


227
String x = (String) null;

Tại sao không có ngoại lệ trong tuyên bố này?

String x = null;
System.out.println(x);

Nó in null. Nhưng .toString()phương pháp nên ném một ngoại lệ con trỏ null.


bạn đang nói về ngoại lệ nào, trình biên dịch?
Sajan Chandran

Câu trả lời:


323

Bạn có thể nullchuyển sang bất kỳ loại tham chiếu nào mà không nhận được bất kỳ ngoại lệ.

Các printlnphương pháp không ném con trỏ null bởi vì nó kiểm tra đầu tiên cho dù đối tượng là null hay không. Nếu null thì nó chỉ đơn giản là in chuỗi "null". Nếu không nó sẽ gọi toStringphương thức của đối tượng đó.

Thêm chi tiết: Phương thức in bên trong gọi String.valueOf(object)phương thức trên đối tượng đầu vào. Và trong valueOfphương thức, kiểm tra này giúp tránh ngoại lệ con trỏ null:

return (obj == null) ? "null" : obj.toString();

Đối với phần còn lại của sự nhầm lẫn của bạn, gọi bất kỳ phương thức nào trên một đối tượng null sẽ ném ngoại lệ con trỏ null, nếu không phải là trường hợp đặc biệt.


1
@JunedAhsan trường hợp đặc biệt nào sẽ khiến nó không ném NPE?
Holloway

@Trengot Kiểm tra một đề cập trong Peter trả lời dưới đây.
Juned Ahsan

144

Bạn có thể truyền nulltới bất kỳ loại tham chiếu nào. Bạn cũng có thể gọi các phương thức xử lý nullnhư một đối số, ví dụ như System.out.println(Object)vậy, nhưng bạn không thể tham chiếu một nullgiá trị và gọi một phương thức trên nó.

BTW Có một tình huống khó khăn khi nó xuất hiện, bạn có thể gọi các phương thức tĩnh trên nullcác giá trị.

Thread t = null;
t.yield(); // Calls static method Thread.yield() so this runs fine.

12
Ồ Nếu được hỏi, tôi sẽ chắc chắn 100% rằng nó sẽ ném một ngoại lệ. Một trường hợp khó khăn thực sự.
Magnilex 17/2/2015

2
@Magnilex: Hoàn toàn đúng! đây là một câu hỏi mẹo thi OCPJP điển hình.
ccpizza 17/03/2016

3
Đây không phải là vì trình biên dịch trong mã byte "tối ưu hóa" nó thành t.yield() -> Thread.yeld() anyway? Tương tự như cách final int i = 1; while (i == 1)được tối ưu hóa thànhwhile(true)
SGal

@SGal Thậm chí còn tốt hơn bởi vì tối ưu hóa thứ hai là AFAIK không bắt buộc trong khi loại thứ nhất là.
Paul Stelian

36

Đây là do thiết kế. Bạn có thể truyền nulltới bất kỳ loại tham chiếu nào. Nếu không, bạn sẽ không thể gán nó cho các biến tham chiếu.


cảm ơn! lưu ý này liên quan đến việc gán null cho các biến tham chiếu là thực sự hữu ích!
Tối đa

22

Việc truyền các giá trị null là bắt buộc để theo cấu trúc sau khi một phương thức bị quá tải và nếu null được truyền cho các phương thức bị quá tải này thì trình biên dịch không biết làm thế nào để xóa sự mơ hồ do đó chúng ta cần đánh máy null trong các trường hợp sau:

class A {
  public void foo(Long l) {
    // do something with l
  }
  public void foo(String s) {
    // do something with s      
  }
}
new A().foo((String)null);
new A().foo((Long)null);

Nếu không, bạn không thể gọi phương thức bạn cần.


Trong hầu hết các trường hợp, việc truyền là ẩn, ví dụ, String bar = null;đưa nullgiá trị thành String. Cho đến nay tôi chỉ phải bỏ null một cách rõ ràng trong một thử nghiệm trong đó một phương thức bị quá tải và tôi muốn kiểm tra hành vi của nó với đầu vào null. Tuy nhiên, thật tốt khi biết, tôi đã viết một câu trả lời tương tự trước khi tôi tìm thấy bạn.
Vlasec

Thực tế thú vị: l instanceof Longs instanceof Stringsẽ trở lại falsetrong những trường hợp này.
Attila Tanyi

7

Println(Object) sử dụng String.valueOf()

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Print(String) không kiểm tra null.

public void print(String s) {
    if (s == null) {
        s = "null";
    }
    write(s);
}

5

Nhiều câu trả lời ở đây đã được đề cập

Bạn có thể truyền null cho bất kỳ loại tham chiếu nào

Nếu đối số là null, thì một chuỗi bằng "null"

Tôi đã tự hỏi nơi đó được chỉ định và tra cứu Đặc tả Java:

Tham chiếu null luôn có thể được gán hoặc chuyển sang bất kỳ loại tham chiếu nào (§5.2, §5.3, §5.5).

Nếu tham chiếu là null, nó được chuyển đổi thành chuỗi "null" (bốn ký tự ASCII n, u, l, l).


3

Như những người khác đã viết, bạn có thể bỏ null cho mọi thứ. Thông thường, bạn sẽ không cần điều đó, bạn có thể viết:

String nullString = null;

mà không đặt diễn viên ở đó.

Nhưng có những dịp mà các diễn viên như vậy có ý nghĩa:

a) nếu bạn muốn đảm bảo rằng một phương thức cụ thể được gọi, như:

void foo(String bar) {  ... }
void foo(Object bar) {  ... }

sau đó nó sẽ làm cho một sự khác biệt nếu bạn gõ

foo((String) null) vs. foo(null)

b) nếu bạn có ý định sử dụng IDE của mình để tạo mã; ví dụ tôi thường viết bài kiểm tra đơn vị như:

@Test(expected=NullPointerException.class)
public testCtorWithNullWhatever() {
    new MyClassUnderTest((Whatever) null);
}

Tôi đang làm TDD; điều này có nghĩa là lớp "MyClassUnderTest" có thể chưa tồn tại. Bằng cách viết mã đó, sau đó tôi có thể sử dụng IDE của mình để tạo lớp mới; và sau đó tạo ra một hàm tạo chấp nhận một đối số "Bất cứ" "ngoài hộp" - IDE có thể hình dung từ thử nghiệm của tôi rằng hàm tạo nên lấy chính xác một đối số kiểu Dù.


2

In :

In một đối tượng. Chuỗi được tạo bởi phương thức String.valueOf (Object) được dịch thành byte

Giá trị :

nếu đối số là null, thì một chuỗi bằng "null"; mặt khác, giá trị của obj.toString () được trả về.

Nó sẽ chỉ đơn giản trả về một chuỗi có giá trị "null" khi đối tượng là null.


2

Điều này rất thuận tiện khi sử dụng một phương pháp mà nếu không thì sẽ mơ hồ. Ví dụ: JDialog có các hàm tạo với các chữ ký sau:

JDialog(Frame, String, boolean, GraphicsConfiguration)
JDialog(Dialog, String, boolean, GraphicsConfiguration)

Tôi cần sử dụng hàm tạo này, vì tôi muốn đặt GraphicsConfiguration, nhưng tôi không có cha mẹ cho hộp thoại này, vì vậy đối số đầu tiên phải là null. Sử dụng

JDialog(null, String, boolean, Graphicsconfiguration) 

không rõ ràng, vì vậy trong trường hợp này tôi có thể thu hẹp cuộc gọi bằng cách chuyển null thành một trong các loại được hỗ trợ:

JDialog((Frame) null, String, boolean, GraphicsConfiguration)

0

Tính năng ngôn ngữ này là thuận tiện trong tình huống này.

public String getName() {
  return (String) memberHashMap.get("Name");
}

Nếu thành viênHashMap.get ("Tên") trả về null, bạn vẫn muốn phương thức trên trả về null mà không ném ngoại lệ. Bất kể lớp học là gì, null là null.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.