Java isteğe bağlı parametreleri


812

Java'da isteğe bağlı parametreleri nasıl kullanabilirim? Hangi spesifikasyon isteğe bağlı parametreleri destekler?

Yanıtlar:


516

varargs bunu yapabilir (bir şekilde). Bunun dışında, yöntemin bildirimindeki tüm değişkenler sağlanmalıdır. Bir değişkenin isteğe bağlı olmasını istiyorsanız, parametreyi gerektirmeyen bir imza kullanarak yöntemi aşırı yükleyebilirsiniz.

private boolean defaultOptionalFlagValue = true;

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

public void doSomething() {
    doSomething(defaultOptionalFlagValue);
}

Bana göre yöntem aşırı yükleme iyi bir cevap, varargs ise çok kötü bir cevap. Lütfen ya varargs hakkındaki yorumu kaldırın ya da birden fazla getiri değeri olasılığının yol açtığı ciddi dezavantajı açıklayın.
Andreas Vogl

Global değişkenler eklemek başka sorunlara neden olabilir.
Helen Cui

1652

Java'da isteğe bağlı parametreleri simüle etmenin birkaç yolu vardır:

  1. Yöntem aşırı yükleme.

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

    Bu yaklaşımın sınırlamalarından biri, aynı tipte iki isteğe bağlı parametreniz varsa ve bunlardan herhangi biri atlanabilirse işe yaramayacağıdır.

  2. Varargs.

    a) İsteğe bağlı tüm parametreler aynı tiptedir:

    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) İsteğe bağlı parametre türleri farklı olabilir:

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

    Bu yaklaşımın ana dezavantajı, isteğe bağlı parametreler farklı tipteyse statik tip kontrolünü kaybetmenizdir. Ayrıca, her bir parametrenin farklı bir anlamı varsa, bunları ayırt etmek için bir yol gerekir.

  3. Boşlara. Önceki yaklaşımların sınırlamalarını gidermek için null değerlere izin verebilir ve ardından bir yöntem gövdesindeki her parametreyi analiz edebilirsiniz:

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

    Şimdi tüm bağımsız değişken değerleri sağlanmalıdır, ancak varsayılan değerler boş olabilir.

  4. İsteğe bağlı sınıf. Bu yaklaşım null değerlerine benzer, ancak varsayılan değeri olan parametreler için Java 8 Optional sınıfını kullanır:

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

    İsteğe bağlı bir yöntem sözleşmesini bir arayan için açık hale getirir, ancak böyle bir imza çok ayrıntılı bulabilir.

    Güncelleme: Java 8, sınıftan java.util.Optionalçıkar çıkmaz sınıfı içerir, bu nedenle Java 8'de bu nedenle guava kullanmaya gerek yoktur. Yöntem adı biraz farklıdır.

  5. Oluşturucu desen. Oluşturucu deseni yapıcılar için kullanılır ve ayrı bir Builder sınıfı eklenerek uygulanır:

     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. Haritalar. Parametre sayısı çok fazla olduğunda ve varsayılan değerlerin çoğu için genellikle kullanıldığında, yöntem bağımsız değişkenlerini adlarının / değerlerinin haritası olarak iletebilirsiniz:

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

    Java 9'da bu yaklaşım daha kolay hale geldi:

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

İstenilen bir sonuç elde etmek için bu yaklaşımlardan herhangi birini birleştirebileceğinizi lütfen unutmayın.


2
@Vitalii Fedorenko Hmm, # 6'da hafif bir kopyala yapıştır hatası yaptığınızı düşünüyorum: aDeğişkeniniz bir String olmasına rağmen (Cast doğrudur) bir Tamsayı için yazım denetimi yapıyorsunuz .
Bilinmeyen Kimlik

5
@Aetos bağlantınız öldü.
Robino

2
@ İsteğe bağlı olarak burada parametre olarak kullanılmaması gerektiğini savunan Robino alternatif bağlantısı . OptionalSeçeneklerden birinde parametre olarak kullanılmasına rağmen , bu cevap çok iyi.
Dherik

Yukarıdaki problemin en yaygın çözümü muhtemelen yöntem aşırı yüklemesidir. Her ne kadar gerçekten bunun bir hayranıydım. Kişisel olarak yapılandırma parametreleri için bir tür tanımlayıcı eklerse tercih ederim.
Alexander Heim

1
bu muhtemelen en iyi cevap olmalı - tümünü kapsar
xproph

104

Java 5.0 ile isteğe bağlı parametreler vardır. Sadece işlevinizi böyle ilan edin:

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

doSomething();veya doSomething(true);şimdi arayabilirsin .


13
Bu aslında doğru cevap. Basit ve kompakt. Java'nın bunları bir dizinin içine koyması için birden fazla parametre alabileceğinizi unutmayın. Örneğin, tek bir parametreyi almak için önce dizinin içeriğini kontrol edersiniz: 'code' boolean flag = (isteğe bağlıFlag.length <1)? False: OptionalFlag [0];
Salvador Valencia

46
Hayır, doğru cevap değildir, çünkü bu tek bir isteğe bağlı parametreye değil, herhangi bir sayıda isteğe bağlı parametreye izin verir. Bu OP'nin istediklerine yakın olsa da, aynı değildir. İhtiyacınız olandan daha fazla parametre kabul etmek potansiyel bir hata ve yanlış anlama kaynağıdır.
sleske

2
Bu şekilde, yalnızca bir isteğe bağlı parametreniz varsa, ancak dizinin uzunluğunu, vb. Denetlemeniz gerekir, bu nedenle süper temiz değil: | "Bir parametre" isteğe bağlı parametre istiyorsanız, o zaman sadece iki yöntem beyan edebilirsiniz (biri aşırı doSomething() { doSomething(true); }
yüklenecek

Birden fazla isteğe bağlı parametre varsa, bu yalnızca tümü aynı veri türündeyse çalışır. Nesne türünü yapabilirsiniz, ama bu gerçekten çirkinleşiyor.
Jay

@Sleske'nin belirttiği gibi, varargs kullanmanın birden fazla değerin geçirilmesine izin vermenin dezavantajı vardır . OP açıkça "isteğe bağlı" için bir çözüm sordu, bu da bir değer veya sıfır anlamına gelir. Bunun nasıl bazılarının iyi bir cevap olduğunu düşünmek bana mahsustur.
Andreas Vogl

99

Bunun gibi bir şey kullanabilirsiniz:

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

paramsDeğişken isteğe bağlıdır. Null olabilecek bir Nesne dizisi olarak ele alınır.

Garip bir şekilde, belgelerde bu konuda hiçbir şey bulamadım, ama işe yarıyor!

Bu, Java 1.5 ve sonraki sürümlerde "yeni" dir (Java 1.4 veya önceki sürümlerde desteklenmez).

Kullanıcı bhoot'un aşağıda da belirttiğini görüyorum.


55

Ne yazık ki Java varsayılan parametreleri doğrudan desteklemiyor.

Ancak, bir dizi JavaBean ek açıklaması yazdım ve bunlardan biri aşağıdaki gibi varsayılan parametreleri destekliyor:

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

Ek açıklama işlemcisi, bunu doğru şekilde desteklemek için yöntem aşırı yükleri oluşturur.

Bkz. Http://code.google.com/p/javadude/wiki/Annotations

Http://code.google.com/p/javadude/wiki/AnnotationsDefaultParametersExample adresindeki tam örnek


53

Java'da isteğe bağlı parametre yoktur. Yapabileceğiniz şey, işlevleri aşırı yüklemek ve ardından varsayılan değerleri iletmektir.

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

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

23

VarArgs ve aşırı yüklemeden bahsedilmiştir. Başka bir seçenek, aşağıdaki gibi görünen bir Oluşturucu kalıbıdır:

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

Her ne kadar bu model bir kurucuda isteğe bağlı parametrelere ihtiyacınız olduğunda en uygun olur.


Bunun için parametre bağımlılığı eklemek istiyorum. sadece param1 ayarladığında param3 ayarlamak istediğimi söylüyor. Örneğin. İlerleme mesajını yalnızca ilerleme durumunu görünür kılarsam ayarlamak istiyorum. isProgressVisible (). setProgressMessage ("yükleme"). bunu nasıl başarabilirim?
Harshal Bhatt

14

JDK> 1.5 sürümünde bu şekilde kullanabilirsiniz;

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

7

Böyle bir yöntem aşırı yükleme kullanarak bir şey yapabilirsiniz.

 public void load(String name){ }

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

Ayrıca @Nullable ek açıklamasını da kullanabilirsiniz

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

ilk parametre olarak null değerini iletmeniz yeterlidir.

Aynı tip değişkenini geçiyorsanız bunu kullanabilirsiniz

public void load(String name...){}

7

Kısa versiyon :

Üç nokta kullanma :

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

(@ VitaliiFedorenko'nun cevabına dayanarak)


2

Aşırı yükleme iyidir, ancak varsayılan değere ihtiyaç duyan çok sayıda değişken varsa, aşağıdakilerle karşılaşırsınız:

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) {  }

Bu yüzden Java tarafından sağlanan Değişken Bağımsız Değişken'i kullanmanızı öneririm. İşte açıklama için bir link .


varargs kullanımı kötü uygulama olarak kabul edilir. sistem böyle (yukarıda belirtilen) yöntemlere ihtiyaç duyuyorsa, sınıf tasarımı kötü göründüğü için yeni bir tasarım düşünmelisiniz.
Diablo

2
Java eksiklikleri için mazeretler hazırlamak ve diğerlerini bu rahatsızlıkları fark etmek ve geçici çözümler tasarlamak için kötü uygulamalarla suçlamak daha da kötü bir uygulamadır.
BrianO

1
Lütfen harici kaynaklara bağlantı vermek yerine ilgili tüm bilgileri cevabınıza ekleyin - verilen bağlantı öldü
Nico Haase

2

Bunun gibi isteğe bağlı değerlerinizi içermek için oluşturucuya çok benzer bir sınıf kullanabilirsiniz.

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

Gibi kullanın

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

Çıktı

someString = something, someInt = 5

Gibi çağırmanız gereken tüm isteğe bağlı değerleri atlamak için foo(o -> {});veya isterseniz foo(), isteğe bağlı parametreleri almayan ikinci bir yöntem oluşturabilirsiniz .

Bu yaklaşımı kullanarak, herhangi bir belirsizlik olmadan herhangi bir sırada isteğe bağlı değerler belirtebilirsiniz. Ayrıca varargs'ın aksine farklı sınıfların parametrelerine sahip olabilirsiniz. Options sınıfını oluşturmak için ek açıklamaları ve kod oluşturmayı kullanabiliyorsanız bu yaklaşım daha da iyi olacaktır.


1

Java artık 1.8'de opsiyonel desteği destekliyor, isteğe bağlı türleri kullanmak için kodu yeniden düzenleyene kadar null kullanıyorum.

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

Object optionalObject = canBeNull();
if (optionalObject != null) {
    // new object returned
} else {
    // no new object returned
}

lütfen örnek verebilir misiniz?
Ocak

1

Varsayılan bağımsız değişkenler Java'da kullanılamaz. C #, C ++ ve Python'da nerede kullanabiliriz ..

Java'da, varsayılan parametreleri olan biri yerine 2 yöntem (işlev) kullanmamız gerekir.

Misal:

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-


28
C # 'ın daha yeni sürümleri varsayılan parametrelere izin verir.
Sogger

2
java herhangi bir parametre için de "..." seçeneğine sahiptir.
Cacho Santa

0

Bu, gerçek Opsiyonel tip tanıtılmadan önce bile eski bir sorudur, ancak bu günlerde birkaç şey düşünebilirsiniz: - yöntem aşırı yüklemesi kullanın - kullanım NULL'ların etrafından geçmekten kaçınma avantajına sahip isteğe bağlı tip Opsiyonel tip genellikle kullanılmadan önce Java 8'de tanıtıldı Google'ın Guava gibi üçüncü taraf lib'lerinden. İsteğe bağlı olarak parametre / argüman olarak kullanmak, asıl amaç bir dönüş süresi olarak kullanmak olduğu için aşırı kullanım olarak düşünülebilir.

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


0

Yöntem aşırı yükleme veya DataType kullanarak isteğe bağlı parametre yapabilirsiniz ...

| * | Yöntem aşırı yükleme:

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

En kolay yol

| * | DataType ... isteğe bağlı parametre olabilir

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

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


8
RetDtaTyp... ciddi anlamda? Yazmak RetDataTypeçok zor mu?
Alexander - Monica'yı eski

Bu koda biraz daha açıklama ekleyebilir misiniz? Bütün bu garip değişkenler ne yapıyor?
Nico Haase

Anlama kolaylığı için değişken isimleri değiştirildi ...
Sujay UN

0

Birden fazla parametreli bir arayüz kullanmayı planlıyorsanız , aşağıdaki yapısal desen kullanılabilir ve gereksiniminize göre bir yöntem uygulayabilir veya geçersiz kılınabilir .

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

0

Bir API uç noktasıysa, "Bahar" ek açıklamalarını kullanmanın zarif bir yolu:

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

Bu durumda innerFunc değişkene ihtiyaç duyacaktır ve api uç noktası olmadığından, bu Bahar ek açıklamasını isteğe bağlı yapmak için kullanamazsınız. Referans: https://www.baeldung.com/spring-request-param

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.