Parameter opsional Java

813

Bagaimana cara menggunakan parameter opsional di Java? Spesifikasi apa yang mendukung parameter opsional?

Mike Pone
sumber

Jawaban:

517

varargs bisa melakukan itu (dengan cara tertentu). Selain itu, semua variabel dalam deklarasi metode harus disediakan. Jika Anda ingin variabel menjadi opsional, Anda bisa membebani metode menggunakan tanda tangan yang tidak memerlukan parameter.

private boolean defaultOptionalFlagValue = true;

public void doSomething(boolean optionalFlag) {
    ...
}

public void doSomething() {
    doSomething(defaultOptionalFlagValue);
}
laginimaineb
sumber
Metode overloading adalah jawaban yang bagus menurut saya, sementara vararg adalah jawaban yang sangat buruk. Harap hapus komentar pada varargs atau jelaskan kerugian serius yang disebabkan oleh kemungkinan lebih dari satu nilai pengembalian.
Andreas Vogl
Menambahkan variabel global dapat menyebabkan beberapa masalah lain.
Helen Cui
1652

Ada beberapa cara untuk mensimulasikan parameter opsional di Jawa:

  1. Metode kelebihan beban.

    void foo(String a, Integer b) {
        //...
    }
    
    void foo(String a) {
        foo(a, 0); // here, 0 is a default value for b
    }
    
    foo("a", 2);
    foo("a");

    Salah satu batasan dari pendekatan ini adalah bahwa itu tidak berfungsi jika Anda memiliki dua parameter opsional dari jenis yang sama dan salah satu dari mereka dapat dihilangkan.

  2. Varargs.

    a) Semua parameter opsional memiliki tipe yang sama:

    void foo(String a, Integer... b) {
        Integer b1 = b.length > 0 ? b[0] : 0;
        Integer b2 = b.length > 1 ? b[1] : 0;
        //...
    }
    
    foo("a");
    foo("a", 1, 2);

    b) Jenis parameter opsional mungkin berbeda:

    void foo(String a, Object... b) {
        Integer b1 = 0;
        String b2 = "";
        if (b.length > 0) {
          if (!(b[0] instanceof Integer)) { 
              throw new IllegalArgumentException("...");
          }
          b1 = (Integer)b[0];
        }
        if (b.length > 1) {
            if (!(b[1] instanceof String)) { 
                throw new IllegalArgumentException("...");
            }
            b2 = (String)b[1];
            //...
        }
        //...
    }
    
    foo("a");
    foo("a", 1);
    foo("a", 1, "b2");

    Kelemahan utama dari pendekatan ini adalah bahwa jika parameter opsional dari tipe yang berbeda Anda kehilangan pemeriksaan tipe statis. Lebih jauh, jika setiap parameter memiliki arti yang berbeda, Anda perlu cara untuk membedakannya.

  3. Nulls. Untuk mengatasi keterbatasan pendekatan sebelumnya, Anda dapat mengizinkan nilai nol dan kemudian menganalisis setiap parameter dalam tubuh metode:

    void foo(String a, Integer b, Integer c) {
        b = b != null ? b : 0;
        c = c != null ? c : 0;
        //...
    }
    
    foo("a", null, 2);

    Sekarang semua nilai argumen harus disediakan, tetapi yang standar mungkin nol.

  4. Kelas opsional. Pendekatan ini mirip dengan nol, tetapi menggunakan kelas Java 8 Opsional untuk parameter yang memiliki nilai default:

    void foo(String a, Optional<Integer> bOpt) {
        Integer b = bOpt.isPresent() ? bOpt.get() : 0;
        //...
    }
    
    foo("a", Optional.of(2));
    foo("a", Optional.<Integer>absent());

    Opsional membuat metode kontrak eksplisit untuk penelepon, namun, orang mungkin menemukan tanda tangan seperti itu terlalu lisan.

    Pembaruan: Java 8 termasuk kelas java.util.Optionalout-of-the-box, jadi tidak perlu menggunakan jambu untuk alasan khusus ini di Jawa 8. Namun nama metode agak berbeda.

  5. Pola pembangun. Pola pembangun digunakan untuk konstruktor dan diimplementasikan dengan memperkenalkan kelas Builder yang terpisah:

     class Foo {
         private final String a; 
         private final Integer b;
    
         Foo(String a, Integer b) {
           this.a = a;
           this.b = b;
         }
    
         //...
     }
    
     class FooBuilder {
       private String a = ""; 
       private Integer b = 0;
    
       FooBuilder setA(String a) {
         this.a = a;
         return this;
       }
    
       FooBuilder setB(Integer b) {
         this.b = b;
         return this;
       }
    
       Foo build() {
         return new Foo(a, b);
       }
     }
    
     Foo foo = new FooBuilder().setA("a").build();
  6. Peta. Ketika jumlah parameter terlalu besar dan untuk sebagian besar nilai default biasanya digunakan, Anda bisa meneruskan argumen metode sebagai peta nama / nilai mereka:

    void foo(Map<String, Object> parameters) {
        String a = ""; 
        Integer b = 0;
        if (parameters.containsKey("a")) { 
            if (!(parameters.get("a") instanceof Integer)) { 
                throw new IllegalArgumentException("...");
            }
            a = (Integer)parameters.get("a");
        }
        if (parameters.containsKey("b")) { 
            //... 
        }
        //...
    }
    
    foo(ImmutableMap.<String, Object>of(
        "a", "a",
        "b", 2, 
        "d", "value")); 

    Di Jawa 9, pendekatan ini menjadi lebih mudah:

        @SuppressWarnings("unchecked")
        static <T> T getParm(Map<String, Object> map, String key, T defaultValue)
        {
            return (map.containsKey(key)) ? (T) map.get(key) : defaultValue;
        }
    
        void foo(Map<String, Object> parameters) {
            String a = getParm(parameters, "a", "");
            int b = getParm(parameters, "b", 0);
            // d = ...
        }
    
        foo(Map.of("a","a",  "b",2,  "d","value"));

Harap dicatat bahwa Anda dapat menggabungkan salah satu dari pendekatan ini untuk mencapai hasil yang diinginkan.

Vitalii Fedorenko
sumber
2
@Vitalii Fedorenko Hmm, saya pikir Anda membuat sedikit kesalahan salin-tempel di # 6: Anda mengetik-memeriksa Integer meskipun avariabel Anda adalah String (pemeran adalah benar).
Id Tidak Diketahui
5
@ Juga, tautan Anda sudah mati.
Robino
2
@Robino tautan alternatif dengan alasan bahwa Opsional tidak boleh digunakan sebagai parameter di sini . Meskipun menggunakan Optionalparameter sebagai di salah satu opsi, jawaban ini sangat bagus.
Dherik
Solusi paling umum untuk masalah di atas mungkin metode overloading. Meskipun saya tidak pernah benar-benar penggemar itu. Secara pribadi saya lebih suka jika mereka menambahkan semacam pengidentifikasi untuk parameter konfigurasi.
Alexander Heim
1
ini mungkin jawaban terbaik - mencakup semua
xproph
104

Ada parameter opsional dengan Java 5.0. Nyatakan fungsi Anda seperti ini:

public void doSomething(boolean... optionalFlag) {
    //default to "false"
    //boolean flag = (optionalFlag.length >= 1) ? optionalFlag[0] : false;
}

Anda bisa menelepon dengan doSomething();atau doSomething(true);sekarang.

bhoot
sumber
13
Ini sebenarnya jawaban yang benar. Sederhana dan kompak. Ingatlah bahwa Anda bisa mendapatkan lebih dari satu parameter sehingga Java menempatkannya di dalam array. Misalnya, untuk mengambil satu parameter, Anda akan memeriksa isi array terlebih dahulu: 'code' boolean flag = (opsionalFlag.length <1)? False: opsionalFlag [0];
Salvador Valencia
46
Tidak, itu bukan jawaban yang benar, karena ini tidak memungkinkan satu parameter opsional, tetapi sejumlah parameter opsional. Meskipun ini dekat dengan apa yang diinginkan OP, itu tidak sama. Ini merupakan sumber bug dan kesalahpahaman potensial untuk menerima lebih banyak parameter daripada yang Anda butuhkan.
sleske
2
Cara ini berfungsi jika Anda hanya memiliki satu parameter opsional, tetapi Anda perlu memeriksa panjang array, dll. Sehingga tidak super bersih: | Jika Anda ingin parameter opsional "satu parameter" maka Anda dapat mendeklarasikan dua metode (satu kelebihan beban doSomething() { doSomething(true); }tidak ada array untuk ditangani, tidak ada ambiguitas
rogerdpack
Jika ada beberapa parameter opsional, ini hanya berfungsi jika semuanya memiliki tipe data yang sama. Nah, Anda bisa membuat objek Object, tapi itu menjadi sangat jelek.
Jay
Seperti @sleske catat, menggunakan varargs memiliki kerugian yang mengerikan dengan membiarkan lebih dari satu nilai diteruskan. OP dengan jelas bertanya tentang solusi untuk "opsional", yang berarti satu nilai atau nol. Bagaimana hal ini dapat dianggap sebagai jawaban yang baik oleh sebagian orang, byond saya.
Andreas Vogl
99

Anda dapat menggunakan sesuatu seperti ini:

public void addError(String path, String key, Object... params) { 
}

Itu params variabel adalah opsional. Itu diperlakukan sebagai array Objek nullable.

Anehnya, saya tidak dapat menemukan apa pun dalam dokumentasi ini, tetapi berhasil!

Ini "baru" di Java 1.5 dan yang lebih tinggi (tidak didukung di Java 1.4 atau sebelumnya).

Saya melihat pengguna bhoot menyebutkan ini juga di bawah.

laluinjagreg
sumber
55

Sayangnya Java tidak mendukung parameter default secara langsung.

Namun, saya telah menulis satu set anotasi JavaBean, dan salah satunya mendukung parameter default seperti berikut:

protected void process(
        Processor processor,
        String item,
        @Default("Processor.Size.LARGE") Size size,
        @Default("red") String color,
        @Default("1") int quantity) {
    processor.process(item, size, color, quantity);
}
public void report(@Default("Hello") String message) {
    System.out.println("Message: " + message);
}

Prosesor anotasi menghasilkan kelebihan metode untuk mendukung hal ini dengan benar.

Lihat http://code.google.com/p/javadude/wiki/Annotations

Contoh lengkap di http://code.google.com/p/javadude/wiki/AnnotationsDefaultParametersExample

Scott Stanchfield
sumber
53

Tidak ada parameter opsional di Jawa. Apa yang dapat Anda lakukan adalah kelebihan fungsi dan kemudian melewati nilai default.

void SomeMethod(int age, String name) {
    //
}

// Overload
void SomeMethod(int age) {
    SomeMethod(age, "John Doe");
}
Dario
sumber
23

VarArgs dan overloading telah disebutkan. Pilihan lain adalah pola Builder, yang akan terlihat seperti ini:

 MyObject my = new MyObjectBuilder().setParam1(value)
                                 .setParam3(otherValue)
                                 .setParam6(thirdValue)
                                 .build();

Meskipun pola itu akan paling tepat ketika Anda membutuhkan parameter opsional di konstruktor.

Yishai
sumber
saya ingin menambahkan dependensi parameter untuk that.let's katakan saya ingin mengatur param3 hanya jika saya mengatur param1. Untuk misalnya. saya ingin mengatur pesan kemajuan hanya jika saya mengatur kemajuan terlihat. isProgressVisible (). setProgressMessage ("memuat"). bagaimana saya bisa mencapainya?
Harshal Bhatt
14

Dalam JDK> 1,5 Anda dapat menggunakannya seperti ini;

public class NewClass1 {

    public static void main(String[] args) {

        try {
            someMethod(18); // Age : 18
            someMethod(18, "John Doe"); // Age & Name : 18 & John Doe
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static void someMethod(int age, String... names) {

        if (names.length > 0) {
            if (names[0] != null) {
                System.out.println("Age & Name : " + age + " & " + names[0]);
            }
        } else {
            System.out.println("Age : " + age);
        }
    }
}
az3
sumber
7

Anda dapat melakukan hal menggunakan metode kelebihan seperti ini.

 public void load(String name){ }

 public void load(String name,int age){}

Anda juga dapat menggunakan anotasi @Nullable

public void load(@Nullable String name,int age){}

cukup berikan null sebagai parameter pertama.

Jika Anda melewati variabel tipe yang sama Anda dapat menggunakan ini

public void load(String name...){}
Ishan Fernando
sumber
7

Versi pendek :

Menggunakan tiga titik :

public void foo(Object... x) {
    String first    =  x.length > 0 ? (String)x[0]  : "Hello";
    int duration    =  x.length > 1 ? Integer.parseInt((String) x[1])     : 888;
}   
foo("Hii", ); 
foo("Hii", 146); 

(berdasarkan jawaban @ VitaliiFedorenko)

T.Todua
sumber
2

Overloading baik-baik saja, tetapi jika ada banyak variabel yang membutuhkan nilai default, Anda akan berakhir dengan:

public void methodA(A arg1) {  }
public void methodA( B arg2,) {  }
public void methodA(C arg3) {  }
public void methodA(A arg1, B arg2) {  }
public void methodA(A arg1, C arg3) {  }
public void methodA( B arg2, C arg3) {  }
public void methodA(A arg1, B arg2, C arg3) {  }

Jadi saya akan menyarankan gunakan Argumen Variabel yang disediakan oleh Java. Berikut tautan untuk penjelasan.

Jigar Shah
sumber
penggunaan varargs dianggap praktik buruk. jika sistem membutuhkan metode (yang disebutkan di atas), maka Anda harus memikirkan desain baru karena desain kelas terlihat buruk.
Diablo
2
Ini bahkan merupakan praktik yang lebih buruk untuk mengarang alasan untuk kekurangan Jawa, dan menuduh orang lain melakukan praktik buruk karena memperhatikan ketidaknyamanan tersebut dan menyusun solusi.
BrianO
1
Harap tambahkan semua informasi yang relevan ke jawaban Anda alih-alih menautkan ke sumber eksternal - tautan yang diberikan sudah mati
Nico Haase
2

Anda bisa menggunakan kelas yang berfungsi seperti pembangun untuk memuat nilai opsional Anda seperti ini.

public class Options {
    private String someString = "default value";
    private int someInt= 0;
    public Options setSomeString(String someString) {
        this.someString = someString;
        return this;
    }
    public Options setSomeInt(int someInt) {
        this.someInt = someInt;
        return this;
    }
}

public static void foo(Consumer<Options> consumer) {
    Options options = new Options();
    consumer.accept(options);
    System.out.println("someString = " + options.someString + ", someInt = " + options.someInt);
}

Gunakan seperti

foo(o -> o.setSomeString("something").setSomeInt(5));

Output adalah

someString = something, someInt = 5

Untuk melewati semua nilai opsional yang Anda harus suka foo(o -> {});atau jika Anda suka, Anda dapat membuat yang keduafoo() metode yang tidak mengambil parameter opsional.

Dengan menggunakan pendekatan ini, Anda dapat menentukan nilai opsional dalam urutan apa pun tanpa ambiguitas. Anda juga dapat memiliki parameter kelas yang berbeda tidak seperti dengan varargs. Pendekatan ini akan lebih baik jika Anda dapat menggunakan anotasi dan pembuatan kode untuk membuat kelas Opsi.

rybai
sumber
1

Java sekarang mendukung opsi dalam 1.8, saya terjebak dengan pemrograman di android jadi saya menggunakan nulls sampai saya bisa memperbaiki kode untuk menggunakan tipe opsional.

Object canBeNull() {
    if (blah) {
        return new Object();
    } else {
        return null;
    }
}

Object optionalObject = canBeNull();
if (optionalObject != null) {
    // new object returned
} else {
    // no new object returned
}
Pelet
sumber
dapatkah Anda memberikan contoh?
sepehr
1

Argumen default tidak dapat digunakan di Jawa. Di mana dalam C #, C ++ dan Python, kita bisa menggunakannya ..

Di Java, kita harus menggunakan 2 metode (fungsi) alih-alih satu dengan parameter default.

Contoh:

Stash(int size); 

Stash(int size, int initQuantity);

http://parvindersingh.webs.com/apps/forums/topics/show/8856498-java-how-to-set-default-parameters-values-like-c-

Parvinder Singh
sumber
28
Versi C # yang lebih baru memungkinkan parameter default.
Sogger
2
java memiliki opsi "..." untuk parameter apa pun juga.
Cacho Santa
0

Ini adalah pertanyaan lama mungkin bahkan sebelum tipe Opsional yang sebenarnya diperkenalkan tetapi hari ini Anda dapat mempertimbangkan beberapa hal: - menggunakan metode overloading - menggunakan tipe Opsional yang memiliki keuntungan menghindari lewat NULL di sekitar tipe Opsional diperkenalkan di Jawa 8 sebelum biasanya digunakan dari lib pihak ketiga seperti Google's Guava. Menggunakan opsional sebagai parameter / argumen dapat dianggap sebagai penggunaan berlebihan karena tujuan utamanya adalah menggunakannya sebagai waktu pengembalian.

Ref: https://itcodehub.blogspot.com/2019/06/using-optional-type-in-java.html

xproph
sumber
0

Kita dapat membuat parameter opsional dengan Metode overloading atau Menggunakan DataType ...

| * | Metode kelebihan beban:

RetDataType NameFnc(int NamePsgVar)
{
    // |* Code Todo *|
    return RetVar;
}

RetDataType NameFnc(String NamePsgVar)
{
    // |* Code Todo *|
    return RetVar;
}

RetDataType NameFnc(int NamePsgVar1, String NamePsgVar2)
{
    // |* Code Todo *|
    return RetVar;
}

Cara termudah adalah

| * | DataType ... bisa menjadi parameter opsional

RetDataType NameFnc(int NamePsgVar, String... stringOpnPsgVar)
{
    if(stringOpnPsgVar.length == 0)  stringOpnPsgVar = DefaultValue; 

    // |* Code Todo *|
    return RetVar;
}

Sujay UN
sumber
8
RetDtaTyp... serius? Apakah RetDataTypeterlalu sulit untuk mengetik?
Alexander - Reinstate Monica
Bisakah Anda menambahkan lebih banyak penjelasan ke kode itu? Apa yang dilakukan oleh semua variabel aneh ini?
Nico Haase
Mengubah nama variabel untuk memudahkan pemahaman ...
Sujay UN
0

Jika Anda berencana untuk menggunakan antarmuka dengan beberapa parameter , seseorang dapat menggunakan pola struktural berikut dan menerapkan atau mengganti berlaku - metode yang didasarkan pada kebutuhan Anda .

public abstract class Invoker<T> {
    public T apply() {
        return apply(null);
    }
    public abstract T apply(Object... params);
}
Mukundhan
sumber
0

Jika titik akhir API, cara yang elegan adalah dengan menggunakan anotasi "Spring":

@GetMapping("/api/foos")
@ResponseBody
public String getFoos(@RequestParam(required = false, defaultValue = "hello") String id) { 
    return innerFunc(id);
}

Perhatikan dalam hal ini bahwa innerFunc akan memerlukan variabel, dan karena itu bukan titik akhir api, tidak dapat menggunakan anotasi Spring ini untuk menjadikannya opsional. Referensi: https://www.baeldung.com/spring-request-param

Sophie Cooperman
sumber