Cách sử dụng null trong chuyển đổi


202
Integer i = ...

switch (i){
    case null:
        doSomething0();
        break;    
    }

Trong đoạn mã trên tôi không thể sử dụng null trong câu lệnh case. Làm thế nào tôi có thể làm điều này khác nhau? Tôi không thể sử dụng defaultvì sau đó tôi muốn làm một cái gì đó khác.


9
trước khi chuyển đổi kiểm tra điều kiện null nếu (i == null) {//
dos Something

8
Điều này thực sự sẽ làm cho việc chuyển đổi hữu ích. Các ngôn ngữ khớp mẫu khác hoạt động theo cách này.
Pyrolistic

Câu trả lời:


276

Điều này là không thể với một switchtuyên bố trong Java. Kiểm tra nulltrước switch:

if (i == null) {
    doSomething0();
} else {
    switch (i) {
    case 1:
        // ...
        break;
    }
}

Bạn không thể sử dụng các đối tượng tùy ý trong các switchcâu lệnh * . Lý do mà trình biên dịch không phàn nàn về switch (i)nơi ilà một Integervì Java tự động hủy hộp thư Integerđến một int. Như assylias đã nói, unboxing sẽ ném một NullPointerExceptionkhi inull.

* Vì Java 7 bạn có thể sử dụng Stringtrong các switchcâu lệnh.

Tìm hiểu thêm về switch(bao gồm ví dụ với biến null) trong Oracle Docs - Switch


16
Bạn cũng có thể sử dụng enums trong câu lệnh switch.
joriki

27
Điều có nghĩa là bạn không thể sử dụng một Integer null hoặc lớp Wrapper khác, vì bỏ hộp. Nhưng những gì về enums và chuỗi? Tại sao chúng không thể là null?
Luân Nico

9
Tôi không hiểu tại sao một mạch ngắn null được ánh xạ tới trường hợp "mặc định" hoặc trường hợp đặc biệt cho chuyển đổi null không được triển khai cho Chuỗi. Nó làm cho việc sử dụng các công tắc để đơn giản hóa mã vô nghĩa vì bạn luôn phải thực hiện kiểm tra null. Tôi không nói đơn giản hóa là chỉ sử dụng cho thiết bị chuyển mạch.
Reimius

3
@Reimius bạn không phải luôn luôn kiểm tra null. Nếu bạn tôn trọng các hợp đồng mã mà bạn đưa ra cho các phương thức của mình, bạn hầu như luôn có thể quản lý để không làm cho mã của bạn bị lộn xộn với các kiểm tra null. Sử dụng khẳng định luôn luôn là tốt đẹp, mặc dù.
Joffrey

Tôi cũng muốn biết câu trả lời cho truy vấn của @ LuanNico. Có vẻ không hợp lý khi nullkhông thể là một trường hợp hợp lệ khi làm việc với Stringenumcác loại. Có lẽ việc enumtriển khai dựa vào việc gọi ordinal()phía sau hậu trường (mặc dù vậy, tại sao không coi nulllà có 'số thứ tự' là -1?), Và Stringphiên bản thực hiện một cái gì đó bằng cách sử dụng intern()và so sánh con trỏ (hoặc nói cách khác là dựa vào thứ gì đó yêu cầu nghiêm ngặt vật)?
aroth


40

switch(i)sẽ ném một NullPulumException nếu tôi có null, bởi vì nó sẽ cố gắng bỏ hộp Integervào int. Vì thếcase null , điều đó xảy ra là bất hợp pháp, dù sao cũng sẽ không bao giờ đạt được.

Bạn cần kiểm tra xem tôi không rỗng trước switchcâu lệnh.


23

Các tài liệu Java đã nêu rõ rằng:

Việc cấm sử dụng null làm nhãn chuyển đổi sẽ ngăn người ta viết mã không bao giờ được thực thi. Nếu biểu thức chuyển đổi là loại tham chiếu, chẳng hạn như loại nguyên thủy được đóng hộp hoặc enum, lỗi thời gian chạy sẽ xảy ra nếu biểu thức ước lượng thành null tại thời gian chạy.

Bạn phải xác minh null trước khi thực thi câu lệnh Swithch.

if (i == null)

Xem Tuyên bố chuyển đổi

case null: // will never be executed, therefore disallowed.

1
Các javadocs tại liên kết của bạn không còn nói "Việc cấm sử dụng null làm nhãn chuyển đổi [vv]".
Patrick M


14

Được:

public enum PersonType {
    COOL_GUY(1),
    JERK(2);

    private final int typeId;
    private PersonType(int typeId) {
        this.typeId = typeId;
    }

    public final int getTypeId() {
        return typeId;
    }

    public static PersonType findByTypeId(int typeId) {
        for (PersonType type : values()) {
            if (type.typeId == typeId) {
                return type;
            }
        }
        return null;
    }
}

Đối với tôi, điều này thường phù hợp với bảng tra cứu trong cơ sở dữ liệu (chỉ dành cho các bảng hiếm khi được cập nhật).

Tuy nhiên, khi tôi cố gắng sử dụng findByTypeIdtrong câu lệnh chuyển đổi (từ, rất có thể, đầu vào của người dùng) ...

int userInput = 3;
PersonType personType = PersonType.findByTypeId(userInput);
switch(personType) {
case COOL_GUY:
    // Do things only a cool guy would do.
    break;
case JERK:
    // Push back. Don't enable him.
    break;
default:
    // I don't know or care what to do with this mess.
}

... như những người khác đã nêu, điều này dẫn đến một NPE @ switch(personType) {. Một cách giải quyết (nghĩa là "giải pháp") tôi bắt đầu thực hiện là thêm một UNKNOWN(-1)loại.

public enum PersonType {
    UNKNOWN(-1),
    COOL_GUY(1),
    JERK(2);
    ...
    public static PersonType findByTypeId(int id) {
        ...
        return UNKNOWN;
    }
}

Bây giờ, bạn không phải thực hiện kiểm tra null nơi nó được tính và bạn có thể chọn hoặc không xử lý UNKNOWNcác loại. (LƯU Ý: -1là một định danh không có khả năng trong kịch bản kinh doanh, nhưng rõ ràng chọn một cái gì đó có ý nghĩa cho trường hợp sử dụng của bạn).


2
UNKNOWNlà giải pháp tốt nhất cho vấn đề này tôi từng thấy và vượt qua nullcheck.
viên

5

Bạn phải làm một

if (i == null) {
   doSomething0();
} else {
   switch (i) {
   }
}

4

Một số thư viện cố gắng cung cấp các lựa chọn thay thế cho câu lệnh java dựng sẵn switch. Vavr là một trong số họ, họ khái quát nó để khớp mẫu.

Đây là một ví dụ từ tài liệu của họ :

String s = Match(i).of(
    Case($(1), "one"),
    Case($(2), "two"),
    Case($(), "?")
);

Bạn có thể sử dụng bất kỳ vị ngữ nào, nhưng họ cung cấp nhiều trong số đó, và $(null)hoàn toàn hợp pháp. Tôi thấy đây là một giải pháp tao nhã hơn các giải pháp thay thế, nhưng điều này đòi hỏi java8 và sự phụ thuộc vào thư viện vavr ...



2
switch (String.valueOf(value)){
    case "null":
    default: 
}

0

Bạn không thể. Bạn có thể sử dụng các nguyên hàm (int, char, short, byte) và String (Chuỗi chỉ trong java 7). nguyên thủy không thể là null.
Kiểm tra itrong điều kiện riêng trước khi chuyển đổi.


4
Bạn có thể sử dụng enums quá.
Karu

5
nếu enum là null, bạn sẽ gặp vấn đề tương tự. BTW, thật lạ khi công tắc không thể xử lý null, vì nó có một điều khoản mặc định

1
@LeonardoKenji Mệnh đề mặc định không thực sự có liên quan đến null; bất cứ điều gì bạn đang chuyển sang nó sẽ được hủy đăng ký để kiểm tra bất kỳ trường hợp nào khác, vì vậy mệnh đề mặc định sẽ không xử lý trường hợp null (một NullPulumException được ném trước khi có cơ hội).
Ben

2
Tôi nghĩ rằng anh ta có nghĩa là mệnh đề mặc định sẽ xử lý null như bất kỳ giá trị enum nào khác có thể không bị bắt bởi trường hợp trước
Leo

0

Chỉ cần xem xét cách SWITCH có thể hoạt động,

  • trong trường hợp nguyên thủy, chúng ta biết rằng nó có thể thất bại với NPE cho quyền anh tự động
  • nhưng đối với String hoặc enum , nó có thể được gọi phương thức bằng, rõ ràng cần một giá trị LHS mà trên đó bằng được gọi. Vì vậy, không có phương thức nào có thể được gọi trên null, chuyển đổi không thể xử lý null.

0

Dựa trên câu trả lời @tetsuo, với java 8:

Integer i = ...

switch (Optional.ofNullable(i).orElse(DEFAULT_VALUE)) {
    case DEFAULT_VALUE:
        doDefault();
        break;    
}
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.