Java可选参数

Java optional parameters

如何在Java中使用可选参数?什么规范支持可选参数?


有几种方法来simulate可选参数:在Java

  • 方法的重载。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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");

    这一方法的局限性是,它不工作,如果你有一个双T型参数和可选的任何他们可以omitted。

  • varargs。

    所有的参数都是可选的)相同的类型:

    1
    2
    3
    4
    5
    6
    7
    8
    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)可选的参数可能是不同的类型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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");

    这种方法的主要缺点是,如果不同类型的可选参数都是静态类型检查,你输了。此外,如果每个参数的意义,你需要有一些不同的方式来distinguish他们。

  • nulls。地址在以前的方法的局限性,你可以允许的,然后分析每个参数的值:在方法体

    1
    2
    3
    4
    5
    6
    7
    void foo(String a, Integer b, Integer c) {
        b = b != null ? b : 0;
        c = c != null ? c : 0;
        //...
    }

    foo("a", null, 2);

    现在,所有的参数值必须被设置,默认的,但可能是空的。。。。。。。。

  • 可选的类。该方法是使用类似于nulls Java类,但这已经是8可选参数的默认值。

    1
    2
    3
    4
    5
    6
    7
    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的类java.util.Optional8包括开箱,所以没有需要使用Java中的番石榴是这个特别的原因。的方法,不同的名字是位而已。

  • 生成器模式。建造模式是用于实现的构造器是由单独的工具类:介绍

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     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();
  • 谷歌地图。当参数的数量太大和是最通常使用的默认值,你可以通过自己的方法参数的名称/值的地图。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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,这对更容易:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        @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"));
  • 请注意,你可以结合任何这些方法desirable实现结果。


    这是可能的varargs(的方式)。这是比其他所有变量的声明,必须提供的方法。如果你想变的过载是可选的,你可以使用签名的方法,这是不是要求的参数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    private boolean defaultOptionalFlagValue = true;

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

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


    你可以使用的东西,像这样:

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

    params变量是可选的。这是一个处理对象的空数组。

    奇怪,我找不到任何关于这个的文件,但它的作品!

    这是一个"新"在1.5和超越(不支持Java在Java 1.4或早期)。

    我看到了下面这bhoot提到的用户。


    有一个用Java 5.0的可选参数。你只是把像这样的函数:

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

    你可以用电话或doSomething(true);doSomething();现在。


    不幸的是,Java不支持默认参数的T头。

    然而,我写的annotations集和一个JavaBean,他们支持默认参数如下列:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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);
    }

    该处理器生成的注释的方法来支持这overloads恰当。

    国有企业code.google.com http:/ / / / / / annotations P javadude维基

    例如,在全code.google.com http:/ / / / / P javadude annotationsdefaultparametersexample维基


    在Java中有可选参数。你可以是一个函数的重载和默认值来传递的。

    1
    2
    3
    4
    5
    6
    7
    8
    void SomeMethod(int age, String name) {
        //
    }

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


    varargs和超载已被提到。另一个选项是一个会看的东西Builder模式,像这样:

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

    虽然这一模式将是最合适的选择是当你需要在构造函数的参数。


    的JDK 1.5中>你可以使用它,像这样。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    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);
            }
        }
    }

    它将取决于你想要实现的在线varargs方法重载,或解决方案,应报。一些好的例子在这里:如何使用它们

    blog.sleekface.com http:/ / / / / Java方法中的核心和可选的参数/

    但在心,不在继续使用方法重载。它带来了混乱。


    短版:

    使用三个点:

    1
    2
    3
    4
    5
    6
    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);

    (基于@vitalifedorenko的答案)


    您可以使用这样的方法重载来完成这项工作。

    1
    2
    3
     public void load(String name){ }

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

    也可以使用@nullable注释

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

    只需将空值作为第一个参数传递。

    如果传递的是同一类型变量,则可以使用

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


    重载是可以的,但是如果有很多变量需要默认值,那么最终会得到:

    1
    2
    3
    4
    5
    6
    7
    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提供的变量参数。这里有一个解释链接。


    Java现在支持OpTales在1.8,我在Android上停留在编程上,所以我使用Null直到我可以重构代码来使用可选类型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Object canBeNull() {
        if (blah) {
            return new Object();
        } else {
            return null;
        }
    }

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


    您可以使用类似于生成器的类来包含这样的可选值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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);
    }

    类使用

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

    输出是

    1
    someString = something, someInt = 5

    要跳过所有的可选值,您必须像foo(o -> {});那样调用它,或者如果您愿意,您可以创建第二个不接受可选参数的foo()方法。

    使用这种方法,您可以按任意顺序指定可选值,而不会产生任何歧义。与varargs不同,您还可以拥有不同类的参数。如果可以使用注释和代码生成来创建选项类,这种方法会更好。


    在Java中不能使用默认参数。在C++、C++和Python中,我们可以使用它们。

    在Java中,我们必须使用2个方法(函数),而不是使用默认参数的方法。

    例子:

    1
    2
    3
    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-


    我们可以通过方法重载或使用数据类型来设置可选参数…

    |*|方法重载:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    RetDtaTyp NamFnc(String NamPsgVar)
    {
        // |* CodTdo *|
        return RetVar;
    }

    RetDtaTyp NamFnc(String NamPsgVar)
    {
        // |* CodTdo *|
        return RetVar;
    }

    RetDtaTyp NamFnc(int NamPsgVar1, String NamPsgVar2)
    {
        // |* CodTdo *|
        return RetVar;
    }

    最简单的方法是

    |*|数据类型…可以是可选参数

    1
    2
    3
    4
    5
    6
    7
    RetDtaTyp NamFnc(int NamPsgVar, String... SrgOpnPsgVar)
    {
        if(SrgOpnPsgVar.length == 0)  SrgOpnPsgVar = DefSrgVar;

        // |* CodTdo *|
        return RetVar;
    }