Java可选参数

Java可选参数,java,optional-parameters,Java,Optional Parameters,如何在Java中使用可选参数?什么规范支持可选参数?varargs可以(以某种方式)做到这一点。除此之外,必须提供方法声明中的所有变量。如果希望变量是可选的,可以使用不需要参数的签名重载方法 private boolean defaultOptionalFlagValue = true; public void doSomething(boolean optionalFlag) { ... } public void doSomething() { doSomething(d

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

varargs可以(以某种方式)做到这一点。除此之外,必须提供方法声明中的所有变量。如果希望变量是可选的,可以使用不需要参数的签名重载方法

private boolean defaultOptionalFlagValue = true;

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

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

Java中没有可选参数。您可以做的是重载函数,然后传递默认值

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

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

已经提到了VarArgs和重载。另一个选项是Bloch Builder模式,其外观如下:

 MyObject my = new MyObjectBuilder().setParam1(value)
                                 .setParam3(otherValue)
                                 .setParam6(thirdValue)
                                 .build();
public void doSomething(boolean... optionalFlag) {
    //default to "false"
    //boolean flag = (optionalFlag.length >= 1) ? optionalFlag[0] : false;
}
public void addError(String path, String key, Object... params) { 
}

尽管这种模式最适合于在构造函数中需要可选参数的情况。

Java 5.0中有可选参数。只需像这样声明您的函数:

 MyObject my = new MyObjectBuilder().setParam1(value)
                                 .setParam3(otherValue)
                                 .setParam6(thirdValue)
                                 .build();
public void doSomething(boolean... optionalFlag) {
    //default to "false"
    //boolean flag = (optionalFlag.length >= 1) ? optionalFlag[0] : false;
}
public void addError(String path, String key, Object... params) { 
}

您可以使用
doSomething()调用
剂量测量(真)现在。

您可以使用如下内容:

 MyObject my = new MyObjectBuilder().setParam1(value)
                                 .setParam3(otherValue)
                                 .setParam6(thirdValue)
                                 .build();
public void doSomething(boolean... optionalFlag) {
    //default to "false"
    //boolean flag = (optionalFlag.length >= 1) ? optionalFlag[0] : false;
}
public void addError(String path, String key, Object... params) { 
}
params
变量是可选的。它被视为可为空的对象数组

奇怪的是,我在文档中找不到这方面的任何信息,但它是有效的

这在Java1.5及更高版本中是“新的”(Java1.4或更早版本不支持)


我看到用户bhoot在下面也提到了这一点。

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

有几种方法可以在Java中模拟可选参数:

  • 方法重载。

    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");
    
    这种方法的一个局限性是,如果有两个相同类型的可选参数,并且其中任何一个都可以忽略,那么它就不起作用

  • Varargs.

    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");
    
    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");
    
    这种方法的主要缺点是,如果可选参数的类型不同,则会丢失静态类型检查。此外,如果每个参数具有不同的含义,则需要某种方法来区分它们

  • 空值。要解决前面方法的局限性,可以允许空值,然后分析方法体中的每个参数:

    void foo(String a, Integer b, Integer c) {
        b = b != null ? b : 0;
        c = c != null ? c : 0;
        //...
    }
    
    foo("a", null, 2);
    
    现在必须提供所有参数值,但默认值可能为null

  • 可选类。此方法类似于nulls,但对具有默认值的参数使用Java 8可选类:

    void foo(String a, Optional<Integer> bOpt) {
        Integer b = bOpt.isPresent() ? bOpt.get() : 0;
        //...
    }
    
    foo("a", Optional.of(2));
    foo("a", Optional.<Integer>absent());
    
  • 映射。当参数数量太多且通常使用大多数默认值时,可以将方法参数作为其名称/值的映射传递:

    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")); 
    
    void foo(映射参数){
    字符串a=“”;
    整数b=0;
    if(parameters.containsKey(“a”){
    如果(!(parameters.get(“a”)instanceof Integer)){
    抛出新的IllegalArgumentException(“…”);
    }
    a=(整数)参数.get(“a”);
    }
    if(parameters.containsKey(“b”){
    //... 
    }
    //...
    }
    foo(不可变映射)(
    “a”,“a”,
    “b”,2,
    “d”、“价值”);
    
    在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"));
    
    @SuppressWarnings(“未选中”)
    静态T getParm(映射映射、字符串键、T defaultValue)
    {
    return(map.containsKey(key))?(T)map.get(key):defaultValue;
    }
    void foo(映射参数){
    字符串a=getParm(参数“a”和“);
    intb=getParm(参数“b”,0);
    //d=。。。
    }
    foo("a,a,b,2,d,value)地图;;
    

  • 请注意,您可以将这些方法中的任何一种结合起来以获得理想的结果。

    默认参数不能在Java中使用。在C++、C++和Python中,我们可以使用它们:>/P>
    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");
    
    在Java中,我们必须使用2个方法(函数),而不是一个带有默认参数的方法

    例如:

    Stash(int size); 
    
    Stash(int size, int initQuantity);
    

    重载是可以的,但是如果有很多变量需要默认值,您将得到:

    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提供的。

    您可以使用如下方法重载

     public void load(String name){ }
    
     public void load(String name,int age){}
    
    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);
    }
    
    也可以使用@Nullable注释

    public void load(@Nullable String name,int age){}
    
    只需将null作为第一个参数传递

    private boolean defaultOptionalFlagValue = true;
    
    public void doSomething(boolean optionalFlag) {
        ...
    }
    
    public void doSomething() {
        doSomething(defaultOptionalFlagValue);
    }
    
    如果要传递相同类型的变量,可以使用

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

    Java现在支持1.8中的optionals,我一直在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
    }
    
    简短版本: 使用三个点

    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的答案)

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

    |*|方法重载:

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

    最简单的方法是

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

    RetDataType NameFnc(int NamePsgVar, String... stringOpnPsgVar)
    {
        if(stringOpnPsgVar.length == 0)  stringOpnPsgVar = DefaultValue; 
    
        // |* Code Todo *|
        return RetVar;
    }
    


    您可以使用一个类似于构建器的类来包含如下可选值

     public void load(String name){ }
    
     public void load(String name,int age){}
    
    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);
    }
    
    输出为

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


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

    这是一个古老的问题,甚至在实际的可选类型被引入之前,但是现在你可以考虑一些事情: -使用方法重载 -使用可选类型,其优点是避免传递空值 在Java8中引入可选类型之前,它通常是从第三方库(如Google的Guava)中使用的。使用可选的参数/参数可以被认为是过度使用,因为它的主要用途是使用它作为返回时间。
    参考:

    如果您计划使用具有多个参数的接口, 您可以使用以下结构模式并实现或覆盖应用-一种基于您的需求的方法

    public abstract class Invoker<T> {
        public T apply() {
            return apply(null);
        }
        public abstract T apply(Object... params);
    }
    
    公共抽象类调用程序{
    公众不适用{