Cara menggunakan null di saklar


202
Integer i = ...

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

Dalam kode di atas saya tidak bisa menggunakan null dalam pernyataan switch case. Bagaimana saya bisa melakukan ini secara berbeda? Saya tidak dapat menggunakan defaultkarena saya ingin melakukan sesuatu yang lain.


9
sebelum beralih periksa kondisi nol jika (i == null) {// dosomething}
Nagaraju Badaeni

8
Ini sebenarnya akan membuat peralihan bermanfaat. Bahasa lain yang cocok dengan pola bekerja dengan cara ini.
Pirolistik

Jawaban:


277

Ini tidak mungkin dengan switchpernyataan di Jawa. Periksa nullsebelum switch:

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

Anda tidak dapat menggunakan objek yang berubah-ubah dalam switchpernyataan * . Alasan bahwa kompiler tidak mengeluh tentang di switch (i)mana iadalah Integeradalah karena Java otomatis membuka kotak Integerke int. Seperti assylias sudah mengatakan, unboxing akan melempar NullPointerExceptionketika iadalah null.

* Sejak Java 7 Anda dapat menggunakan Stringdi switchpernyataan.

Lebih lanjut tentang switch(termasuk contoh dengan variabel nol) di Oracle Docs - Switch


16
Anda juga dapat menggunakan enum dalam pernyataan sakelar.
joriki

27
Masuk akal bahwa Anda tidak dapat menggunakan Integer null atau kelas Wrapper lainnya, karena unboxing. Tetapi bagaimana dengan enum dan string? Mengapa tidak bisa nol?
Luan Nico

9
Saya tidak mengerti mengapa hubung singkat null dipetakan ke case "default" atau case khusus untuk switch null tidak diterapkan untuk Strings. Itu membuat menggunakan switch untuk menyederhanakan kode tidak berguna karena Anda selalu harus melakukan pemeriksaan nol. Saya tidak mengatakan penyederhanaan adalah satu-satunya penggunaan untuk switch.
Reimius

3
@Reimius Anda tidak selalu harus melakukan cek nol. Jika Anda menghormati kontrak kode yang Anda berikan kepada metode Anda, Anda dapat hampir selalu berhasil tidak memiliki kode Anda penuh dengan cek null. Namun, menggunakan penegasan selalu menyenangkan.
Joffrey

Saya juga ingin tahu jawaban atas permintaan @ LuanNico. Tampaknya tidak masuk akal bahwa nulltidak bisa menjadi kasus yang valid ketika bekerja dengan Stringdan enummengetik. Mungkin enumimplementasinya bergantung pada panggilan di ordinal()belakang layar (meskipun demikian, mengapa tidak memperlakukan nullsebagai 'ordinal' dari -1?), DanString versi melakukan sesuatu menggunakan intern()dan perbandingan-pointer (atau sebaliknya bergantung pada sesuatu yang sangat membutuhkan dereferencing dan obyek)?
aroth

98
switch ((i != null) ? i : DEFAULT_VALUE) {
        //...
}

cara yang lebih bersih daripada menggunakan satu ekstra jika lain
Vivek Agrawal

40

switch(i) akan melempar NullPointerException jika iya null iya, karena akan mencoba membuka kotaknya Integerke dalam int. Jadi case null, yang kebetulan ilegal, toh tidak akan pernah tercapai.

Anda perlu memeriksa bahwa saya tidak nol sebelum switchpernyataan itu.


23

Java docs dengan jelas menyatakan bahwa:

Larangan menggunakan null sebagai label saklar mencegah seseorang dari menulis kode yang tidak pernah dapat dieksekusi. Jika ekspresi switch adalah tipe referensi, seperti tipe primitif kotak atau enum, kesalahan run-time akan terjadi jika ekspresi mengevaluasi ke nol pada saat run-time.

Anda harus memverifikasi null sebelum eksekusi pernyataan Swithch.

if (i == null)

Lihat Pernyataan Beralih

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

1
Javascript di tautan Anda tidak lagi mengatakan "Larangan menggunakan null sebagai label sakelar [dll]".
Patrick M


14

Diberikan:

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

Bagi saya, ini biasanya selaras dengan tabel pencarian dalam database (hanya untuk tabel yang jarang diperbarui).

Namun, ketika saya mencoba untuk menggunakan findByTypeIddalam pernyataan switch (dari, kemungkinan besar, input pengguna) ...

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

... seperti yang telah dinyatakan orang lain, ini menghasilkan NPE @ switch(personType) {. Satu solusi (yaitu, "solusi") yang saya mulai terapkan adalah menambahkan sebuah UNKNOWN(-1)tipe.

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

Sekarang, Anda tidak perlu melakukan pemeriksaan nol di mana ia penting dan Anda dapat memilih untuk, atau tidak, menangani UNKNOWNjenis. (CATATAN: -1adalah pengidentifikasi yang tidak mungkin dalam skenario bisnis, tetapi jelas memilih sesuatu yang masuk akal untuk kasus penggunaan Anda).


2
UNKNOWNadalah solusi terbaik untuk ini yang pernah saya lihat dan mengalahkan nullchecks.
membersound

5

Anda harus membuat

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

4

Beberapa perpustakaan mencoba untuk menawarkan alternatif untuk switchpernyataan java builtin . Vavr adalah salah satunya, mereka menggeneralisasikannya ke pencocokan pola.

Ini adalah contoh dari dokumentasi mereka :

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

Anda dapat menggunakan predikat apa pun, tetapi mereka menawarkan banyak di antaranya, dan $(null)sangat sah. Saya menemukan ini solusi yang lebih elegan daripada alternatif, tetapi ini memerlukan java8 dan ketergantungan pada perpustakaan vavr ...



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

0

Kamu tidak bisa Anda dapat menggunakan primitif (int, char, short, byte) dan String (Strings in java 7 only) di switch. primitif tidak boleh nol.
Periksa idalam kondisi terpisah sebelum beralih.


4
Anda juga bisa menggunakan enum.
Karu

5
jika enum adalah nol, Anda akan memiliki masalah yang sama. BTW, itu cukup aneh bahwa switch tidak dapat menangani null, karena memiliki klausa default

1
@LeonardoKenji Klausa default tidak benar-benar ada hubungannya dengan null; apa pun yang Anda aktifkan akan ditereferensi untuk memeriksa kasus lain, sehingga klausa default tidak akan menangani kasus nol (NullPointerException dilempar sebelum memiliki kesempatan untuk).
Ben

2
Saya pikir maksudnya klausa default harus menangani null sebagai kemungkinan nilai enum lain yang tidak ditangkap oleh kasus sebelumnya
Leo

0

Pertimbangkan saja bagaimana SWITCH mungkin bekerja,

  • dalam kasus primitif kita tahu itu bisa gagal dengan NPE untuk auto-tinju
  • tetapi untuk String atau enum , itu mungkin menggunakan metode equals, yang jelas membutuhkan nilai LHS di mana equals sedang dipanggil. Jadi, mengingat tidak ada metode yang dapat dipanggil pada null, switch tidak dapat menangani null.

0

Berdasarkan jawaban @tetsuo, dengan java 8:

Integer i = ...

switch (Optional.ofNullable(i).orElse(DEFAULT_VALUE)) {
    case DEFAULT_VALUE:
        doDefault();
        break;    
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.