Javaオプションパラメータ


813

Javaでオプションのパラメーターを使用するにはどうすればよいですか?オプションのパラメーターをサポートする仕様は何ですか?

回答:


517

varargsはそれを(ある意味で)行うことができます。それ以外は、メソッドの宣言内のすべての変数を指定する必要があります。変数をオプションにする場合は、パラメータを必要としないシグネチャを使用してメソッドをオーバーロードできます。

private boolean defaultOptionalFlagValue = true;

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

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

メソッドのオーバーロードは私の意見では良い答えですが、可変引数は非常に悪い答えです。可変引数に関するコメントを削除するか、複数の戻り値の可能性によって引き起こされる重大な欠点を説明してください。
Andreas Vogl

グローバル変数を追加すると、他の問題が発生する可能性があります。
Helen Cui

1652

Javaでオプションのパラメーターをシミュレートする方法はいくつかあります。

  1. メソッドのオーバーロード。

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

    このアプローチの制限の1つは、同じタイプの2つのオプションパラメーターがあり、それらのいずれかを省略できる場合は機能しないことです。

  2. Varargs。

    a)すべてのオプションパラメータは同じタイプです。

    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)オプションパラメータのタイプは異なる場合があります。

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

    このアプローチの主な欠点は、オプションのパラメーターの型が異なる場合、静的型チェックが失われることです。さらに、各パラメーターの意味が異なる場合は、それらを区別する方法が必要です。

  3. ヌル。以前のアプローチの制限に対処するには、null値を許可してから、メソッド本体の各パラメーターを分析します。

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

    すべての引数の値を指定する必要がありますが、デフォルトの値はnullの場合があります。

  4. オプションのクラス。このアプローチはnullに似ていますが、デフォルト値を持つパラメーターにJava 8 Optionalクラスを使用します。

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

    オプションは、呼び出し元に対してメソッドコントラクトを明示的にしますが、そのようなシグネチャは冗長すぎる場合があります。

    更新:Java 8にはjava.util.Optional標準のクラスが含まれているため、Java 8ではこの特定の理由によりguavaを使用する必要はありません。ただし、メソッド名は少し異なります。

  5. ビルダーのパターン。ビルダーパターンはコンストラクターに使用され、別のビルダークラスを導入することで実装されます。

     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. マップ。パラメータの数が多すぎて、ほとんどのデフォルト値が通常使用される場合、名前/値のマップとしてメソッド引数を渡すことができます。

    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では、このアプローチがより簡単になりました。

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

これらのアプローチのいずれかを組み合わせて、望ましい結果を得ることができることに注意してください。


2
@Vitalii Fedorenkoうーん、#6で少しコピーと貼り付けを間違えたと思います。a変数は文字列ですが(キャストは正しい)、整数の型チェックを行っています。
不明なID

5
@Aetosあなたのリンクは死んでいます。
ロビノ2017年

2
@Robinoの代替リンク。ここではOptionalをパラメーターとして使用しないでくださいOptionalオプションの1つでasパラメータを使用しているにもかかわらず、この回答は非常に適切です。
デリック2018

上記の問題に対する最も一般的な解決策は、おそらくメソッドのオーバーロードです。私はそのファンではありませんでしたが。個人的には、構成パラメータになんらかの識別子を追加したほうがよいでしょう。
Alexander Heim

1
これはおそらく最良の答えになるはずです-すべてをカバーします
xproph

104

Java 5.0にはオプションのパラメーターがあります。次のように関数を宣言してください:

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

あなたは、doSomething();またはdoSomething(true);今すぐ電話することができます。


13
これが正解です。シンプルでコンパクトです。Javaが配列内にそれらを配置するように、複数のパラメーターを取得できることを覚えておいてください。たとえば、単一のパラメーターを取得するには、まず配列の内容を確認します。 'code'ブールフラグ=(optionalFlag.length <1)?false:optionalFlag [0];
サルバドールバレンシア

46
いいえ、これは正解ではありません。これは、単一のオプションパラメータではなく、任意の数のオプションパラメータを許可するためです。これはOPが望むものに近いですが、同じではありません。必要以上のパラメータを受け入れることは、バグや誤解の潜在的な原因になります。
sleske 2014年

2
この方法は、オプションのパラメーターが1つしかない場合に機能しますが、配列の長さなどを確認する必要があるため、非常にクリーンではありません。「1つのパラメーター」のオプションパラメーターが必要な場合は、2つのメソッドを宣言することもできます(1つdoSomething() { doSomething(true); }は処理する配列をオーバーロードせず、あいまいさはありません
rogerdpack

複数のオプションのパラメーターがある場合、これは、それらがすべて同じデータ型である場合にのみ機能します。まあ、あなたはオブジェクト型を作ることができますが、それは本当に醜くなってきています。
ジェイ

@sleskeが述べたように、varargsを使用すると、複数の値を渡すことができるという大きな欠点があります。OPは、「オプション」の解決策について明確に尋ねました。これは、1つの値または0を意味します。一部の人がこれをどのようにして適切な回答と見なすことができるかは、私によって異なります。
Andreas Vogl

99

次のようなものを使用できます。

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

params変数はオプションです。オブジェクトのnull可能な配列として扱われます。

不思議なことに、ドキュメントでこれについて何も見つけることができませんでしたが、動作します!

これは、Java 1.5以降では「新規」です(Java 1.4以前ではサポートされていません)。

ユーザーbhootがこれについても以下で説明しているのがわかります。


55

残念ながら、Javaはデフォルトのパラメータを直接サポートしていません。

ただし、JavaBeanアノテーションのセットを作成しましたが、そのうちの1つは次のようなデフォルトパラメータをサポートしています。

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

注釈プロセッサは、これを適切にサポートするためにメソッドオーバーロードを生成します。

http://code.google.com/p/javadude/wiki/Annotationsを参照してください

http://code.google.com/p/javadude/wiki/AnnotationsDefaultParametersExampleの完全な例


53

Javaにはオプションのパラメーターはありません。あなたができることは、関数をオーバーロードしてデフォルト値を渡すことです。

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

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

23

VarArgsとオーバーロードについては言及されています。別のオプションは、次のようなビルダーパターンです。

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

ただし、そのパターンは、コンストラクターでオプションのパラメーターが必要な場合に最適です。


そのためにパラメーターの依存関係を追加したいとします。たとえば、param1を設定した場合にのみparam3を設定したいとします。たとえば 進行状況を表示するように設定した場合にのみ、進行状況メッセージを設定します。isProgressVisible()。setProgressMessage( "loading")。どうすればそれを達成できますか?
Harshal Bhatt

14

JDK> 1.5では、次のように使用できます。

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

このようにメソッドのオーバーロードを使用して処理を行うことができます。

 public void load(String name){ }

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

また、@ Nullableアノテーションを使用できます

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

最初のパラメータとしてnullを渡すだけです。

同じ型の変数を渡す場合は、これを使用できます

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

7

短縮版 :

3つのドットを使用 :

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の回答に基づく)


2

オーバーロードは問題ありませんが、デフォルト値を必要とする変数がたくさんある場合、次のようになります。

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

したがって、Javaが提供する変数引数を使用することをお勧めします。ここに説明のリンクがあります。


可変引数の使用は悪い習慣と考えられています。システムがそのような(上記の)メソッドを必要とする場合、クラスのデザインが悪いように見えるため、新しいデザインを考える必要があります。
ディアブロ2017

2
Javaの欠陥の言い訳をして、他の人にそれらの不便に気づき、回避策を考案した悪い習慣を非難することはさらに悪い習慣です。
BrianO

1
外部ソースにリンクするのではなく、すべての関連情報を回答に追加してください-指定されたリンクは
無効

2

ビルダーのように機能するクラスを使用して、このようなオプション値を含めることができます。

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

のように使う

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

出力は

someString = something, someInt = 5

必要に応じて呼び出す必要があるすべてのオプション値をスキップするには、foo(o -> {});またはfoo()必要に応じて、オプションパラメータを受け取らない2番目のメソッドを作成できます。

このアプローチを使用すると、あいまいさを伴わずにオプションの値を任意の順序で指定できます。varargsとは異なり、さまざまなクラスのパラメーターを持つこともできます。この方法は、注釈とコード生成を使用してOptionsクラスを作成できる場合はさらに優れています。


1

Javaは1.8でオプションをサポートするようになり、Androidでのプログラミングに行き詰まっているので、コードをリファクタリングしてオプションの型を使用できるようになるまでnullを使用しています。

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

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

例を挙げていただけますか?
sepehr 2017年

1

デフォルトの引数はJavaでは使用できません。C#、C ++、Pythonでは、それらを使用できます。

Javaでは、デフォルトのパラメーターを持つメソッドではなく、2つのメソッド(関数)を使用する必要があります。

例:

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#の新しいバージョンでは、デフォルトのパラメーターを使用できます。
Sogger 2013

2
javaには、任意のパラメーターの「...」オプションもあります。
カチョサンタ2013

0

これはおそらく実際のオプション型が導入される前でも古い質問ですが、最近ではいくつかのことを考慮することができます。グーグルのグアバなどのサードパーティのlibから。オプションのパラメーター/引数として使用することは、主な目的が戻り時間としてそれを使用することであったため、過度の使用と見なすことができます。

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


0

メソッドのオーバーロードまたはDataTypeの使用により、オプションのパラメーターを作成できます...

| * | メソッドのオーバーロード:

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

最も簡単な方法は

| * | DataType ...はオプションのパラメーターにすることができます

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

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


8
RetDtaTyp...本気?あるRetDataTypeうちに入力するにはあまりにも難しいですか?
アレクサンダー-モニカ

そのコードにもう少し説明を追加できますか?これらすべての奇妙な変数は何をしますか?
Nico Haase

わかりやすくするために変数名を変更しました...
Sujay UN '10 / 10/30

0

複数のパラメーターを持つインターフェースを使用することを計画している場合は、次の構造パターンを使用して、applyを実装またはオーバーライドできます要件に基づいたメソッドです

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

0

APIエンドポイントの場合、エレガントな方法は「Spring」アノテーションを使用することです。

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

この場合、innerFuncは変数を必要とし、それはAPIエンドポイントではないため、このSpringアノテーションを使用してオプションにすることができないことに注意してください。リファレンス:https : //www.baeldung.com/spring-request-param

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.