web-dev-qa-db-ja.com

Javaはデフォルトのパラメータ値をサポートしていますか?

次のような構造のJavaコードに出会いました。

public MyParameterizedFunction(String param1, int param2)
{
    this(param1, param2, false);
}

public MyParameterizedFunction(String param1, int param2, boolean param3)
{
    //use all three parameters here
}

C++では、パラメータにデフォルト値を代入できることを知っています。例えば:

void MyParameterizedFunction(String param1, int param2, bool param3=false);

Javaはこの種の構文をサポートしていますか?この2ステップ構文が望ましい理由はありますか?

1465
gnavi

いいえ、見つかった構造は、Javaがそれを処理する方法です(つまり、デフォルトパラメータの代わりにオーバーロードを使用します)。

コンストラクタの場合、オーバーロードが複雑になる場合は、 『有効なJava:プログラミング言語ガイド』の項目1のヒント(コンストラクタではなく静的ファクトリメソッドを検討してください)を参照してください。他の方法では、場合によっては名前を変更するか、パラメータオブジェクトを使用すると効果的です。十分な複雑さがあるため、差別化が困難になります。明確な場合は、数や型だけでなく、パラメータの順序を使用して区別しなければならない場合です。

838
Kathy Van Stone

いいえ、しかし このStack Overflow answer で説明されているように、 Builderパターン を使用できます。

リンク先の回答で説明されているように、Builderパターンを使用すると、次のようなコードを書くことができます。

Student s1 = new StudentBuilder().name("Eli").buildStudent();
Student s2 = new StudentBuilder()
                 .name("Spicoli")
                 .age(16)
                 .motto("Aloha, Mr Hand")
                 .buildStudent();

一部のフィールドはデフォルト値を持つことができるか、そうでなければオプションになることができます。

584
Eli Courtwright

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. バラッグ。

    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。 以前のアプローチの制限に対処するために、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());
    

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

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

     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 = (String)parameters.get("a");
        } else if (parameters.containsKey("b")) { 
            //... 
        }
        //...
    }
    
    foo(ImmutableMap.<String, Object>of(
        "a", "a",
        "b", 2, 
        "d", "value")); 
    

あなたが望ましい結果を達成するためにあなたがこれらのアプローチのどれでも組み合わせることができることに注意してください。

406

悲しいことに、いいえ。

218
Rob H

残念ながらそうです。

void MyParameterizedFunction(String param1, int param2, bool param3=false) {}

java 1.5では次のように書くことができます。

void MyParameterizedFunction(String param1, int param2, Boolean... params) {
    assert params.length <= 1;
    bool param3 = params.length > 0 ? params[0].booleanValue() : false;
}

しかし、あなたがコンパイラを生成するコンパイラについてあなたがどのように感じるかに頼るべきかどうか

new Boolean[]{}

通話ごとに。

複数のデフォルト設定可能なパラメータの場合:

void MyParameterizedFunction(String param1, int param2, bool param3=false, int param4=42) {}

java 1.5では次のように書くことができます。

void MyParameterizedFunction(String param1, int param2, Object... p) {
    int l = p.length;
    assert l <= 2;
    assert l < 1 || Boolean.class.isInstance(p[0]);
    assert l < 2 || Integer.class.isInstance(p[1]);
    bool param3 = l > 0 && p[0] != null ? ((Boolean)p[0]).booleanValue() : false;
    int param4 = l > 1 && p[1] != null ? ((Integer)p[1]).intValue() : 42;
}

これはC++構文と一致します。これは、パラメータリストの最後にデフォルトのパラメータしか許されないためです。

構文を超えて、これが渡されたデフォルト可能なパラメータのためのランタイム型チェックとC++型がコンパイル中にそれらをチェックするところに違いがあります。

80
ebelisle

いいえ、できますが、簡単にエミュレートできます。 C++の内容は次のとおりです。

public: void myFunction(int a, int b=5, string c="test") { ... }

Javaでは、それはオーバーロードされた関数になります。

public void myFunction(int a, int b, string c) { ... }

public void myFunction(int a, int b) {
    myFunction(a, b, "test");
}

public void myFunction(int a) {
    myFunction(a, 5);
}

先に述べたように、デフォルトパラメータは関数のオーバーロードにおいてあいまいなケースを引き起こします。それは単に真実ではない、我々はC++の場合に見ることができる:はい、多分それはあいまいなケースを作成することができるが、これらの問題は簡単に処理することができる。それは単純にJavaで開発されたのではありません。おそらく、作成者がC++のようにもっと単純な言語を望んでいたためです。しかし、私たちのほとんどは、その単純さのために彼がJavaを使っているとは思わない。

35
peterh

これは、JVM上で動作し、Javaプログラムと互換性のあるScalaで行うことができます。 http://www.scala-lang.org/

すなわち.

class Foo(var prime: Boolean = false, val rib: String)  {}
20
lythic

私はここで明白なことを述べているかもしれませんが、なぜ単にあなた自身で "default"パラメータを実装しないのですか?

public class Foo() {
        public void func(String s){
                func(s, true);
        }
        public void func(String s, boolean b){
                //your code here
        }
}

デフォルトではあなたが使うことになるでしょう

func( "my string");

デフォルトを使いたくない場合は、

func( "my string"、false);

11
IronWolf

いいえ 、しかし これを実装するための最も簡単な方法

public myParameterizedFunction(String param1, int param2, Boolean param3) {

    param3 = param3 == null ? false : param3;
}

public myParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}

または、三項演算子の代わりに次の場合に使用できます。

public myParameterizedFunction(String param1, int param2, Boolean param3) {

    if (param3 == null) {
        param3 = false;
    }
}

public myParameterizedFunction(String param1, int param2) {

    this(param1, param2, false);
}
10
simhumileco

いいえ。一般的にJavaは単純な言語を作ろうとしていたので、構文上の糖はそれほど多くありません。

6
tomjen

いいえ.

スマートデフォルトを持つオブジェクトを渡すことで同じ動作を実現できます。しかし、これもまた、あなたの訴訟がどうなっているかによって異なります。

6
Santosh Gokak

Scalaが述べたように、 Kotlin も言及する価値があります。 Kotlinでは、関数パラメータはデフォルト値を持つことができ、他のパラメータを参照することさえできます。

fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {
    ...
}

Scalaと同様に、KotlinはJVM上で動作し、既存のJavaプロジェクトに簡単に統合することができます。

4
mrts

これはサポートされていませんが、いくつかの構文シュガーでパラメータオブジェクトパターンを使用するようないくつかのオプションがあります。

public class Foo() {
    private static class ParameterObject {
        int param1 = 1;
        String param2 = "";
    }

    public static void main(String[] args) {
        new Foo().myMethod(new ParameterObject() {{ param1 = 10; param2 = "bar";}});
    }

    private void myMethod(ParameterObject po) {
    }
}

このサンプルでは、​​デフォルト値でParameterObjectを作成し、クラスインスタンス初期化セクション{ param1 = 10; param2 = "bar";}でそれらをオーバーライドします。

4
hoaz

この解決策を試してください。

public int getScore(int score, Integer... bonus)
{
    if(bonus.length > 0)
    {
        return score + bonus[0];
    }

    return score;
}
3
Hamzeh Soboh

Java Method Invocation Builder を使用すると、デフォルト値で自動的にBuilderを生成できます。

クラスまたはインタフェースに@GenerateMethodInvocationBuilderを追加し、デフォルト値が必要なメソッドのパラメータに@Defaultを追加するだけです。注釈で指定したデフォルト値を使用して、コンパイル時にビルダーが生成されます。

@GenerateMethodInvocationBuilder
public class CarService {
 public CarService() {
 }

 public String getCarsByFilter(//
   @Default("Color.BLUE") Color color, //
   @Default("new ProductionYear(2001)") ProductionYear productionYear,//
   @Default("Tomas") String owner//
 ) {
  return "Filtering... " + color + productionYear + owner;
 }
}

そしてメソッドを呼び出すことができます。

CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
  .invoke(instance);

または、デフォルト値を他の値に設定します。

CarService instance = new CarService();
String carsByFilter = CarServiceGetCarsByFilterBuilder.getCarsByFilter()//
  .withColor(Color.YELLOW)//
  .invoke(instance);
2
Tomas Bjerre

Java 8で動作する https://stackoverflow.com/a/13864910/2323964 への同様のアプローチは、デフォルトのゲッターを持つインターフェースを使用することです。これは余白が冗長になりますが、あやふやなので、実際にパラメータに注意を向けたいインスタンスがたくさんあるときには最適です。

public class Foo() {
    public interface Parameters {
        String getRequired();
        default int getOptionalInt(){ return 23; }
        default String getOptionalString(){ return "Skidoo"; }
    }

    public Foo(Parameters parameters){
        //...
    }

    public static void baz() {
        final Foo foo = new Foo(new Person() {
            @Override public String getRequired(){ return "blahblahblah"; }
            @Override public int getOptionalInt(){ return 43; }
        });
    }
}
2
Novaterata

このような半ダース以上の問題があります、最終的には静的な工場出荷時のパターンに到達します...それについては暗号APIを参照してください。説明するのは難しいですが、このように考えてください。コンストラクタがある場合は、デフォルトまたはその他の方法で、波かっこを超えて状態を伝播する唯一の方法は、ブールのisValidを使用することです。 (デフォルト値としてのnullと共にvコンストラクタに失敗した場合)、またはフィールドユーザから返されるときには決して意味のない例外をスローします。

Code Correctは駄目です、私は1000行のコンストラクタを書き、必要なことをします。私はオブジェクトの構築時にisValidを使っていることに気付きました - 言い換えれば、2行のコンストラクタ - ですが、何らかの理由で静的ファクトリパターンに移行しています。私はあなたがメソッド呼び出しの中であなたが多くをすることができるように思えます、まだsync()問題がありますが、デフォルトはより良い(より安全な)代用することができます

ここでやらなければならないことは、デフォルト値としてnullの問題に対処することです。String one = new String( "");メンバ変数として、コンストラクタに渡された文字列を代入する前にnullのチェックを行います。

Javaで行われている生の成層圏コンピューター科学の量は非常に驚くべきです。

C++などにはベンダーライブラリがあります。それは巨大なツールボックスであるため、Javaは大規模サーバーでそれらを追い越すことができます。静的イニシャライザブロックを勉強して、私たちと一緒にいましょう。

1
Nicholas Jordan

これが私のやり方です…あなたの定義したパラメータに対して 'オプションの引数'を持つのと同じくらい便利ではありませんが、それは仕事を完成させます:

public void postUserMessage(String s,boolean wipeClean)
{
    if(wipeClean)
    {
        userInformation.setText(s + "\n");
    }
    else
    {
        postUserMessage(s);
    }
}

public void postUserMessage(String s)
{
    userInformation.appendText(s + "\n");
}

同じメソッド名を文字列だけで呼び出すことも、文字列とブール値を使って呼び出すこともできます。この場合、wipeCleanをtrueに設定すると、私のTextArea内のすべてのテキストが提供された文字列に置き換えられます。 wipeCleanをfalseに設定するか、まとめて省略すると、提供されたテキストがTextAreaに追加されるだけです。

また、2つのメソッドでコードを繰り返すのではなく、追加されたブール値だけを使用して同じ名前の新しいメソッドを作成することによってTextAreaをリセットできるという機能を追加するだけです。

デフォルト値などをコーディングする必要があるので、実際にはこれはJavaがパラメータに 'オプションの引数'を指定した場合よりも少しきれいだと思います。はい、私は私のクラスにさらに別のメソッドを追加しました、しかし私の控え目な意見では長期的に読む方が簡単です。

1
Michael Sims

いいえ、しかし関数オーバーロードという形で代替手段があります。

パラメータが渡されなかったときに呼び出されます

void operation(){

int a = 0;
int b = 0;

} 

"a"パラメータが渡されたときに呼び出されます

void operation(int a){

int b = 0;
//code

} 

パラメータbが渡されたときに呼び出されます

void operation(int a , int b){
//code
} 
0
Umair Khalid

私は値を返すメソッドでこれを使う方法を理解するのにかなりの時間を費やしました、そして今まで例を見たことがありません、私はここにこれを追加することが役に立つかもしれないと思いました:

int foo(int a) {
    // do something with a
    return a;
}

int foo() {
    return foo(0); // here, 0 is a default value for a
}
0
AAGD