代码之家  ›  专栏  ›  技术社区  ›  Mike Pone

Java可选参数

  •  690
  • Mike Pone  · 技术社区  · 15 年前

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

    16 回复  |  直到 5 年前
        1
  •  440
  •   WarFox    13 年前

    瓦拉格斯可以这样做(在某种程度上)。除此之外,必须提供方法声明中的所有变量。如果希望变量是可选的,可以使用不需要参数的签名来重载方法。

    private boolean defaultOptionalFlagValue = true;
    
    public void doSomething(boolean optionalFlag) {
        ...
    }
    
    public void doSomething() {
        doSomething(defaultOptionalFlagValue);
    }
    
        2
  •  1480
  •   Mehran    6 年前

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

      这种方法的一个局限性是,如果您有两个相同类型的可选参数,并且其中任何参数都可以省略,那么它就不起作用。

    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. 空值。 要解决前面方法的局限性,可以允许空值,然后分析方法体中的每个参数:

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

      现在必须提供所有参数值,但默认值可能为空。

    4. 选修课。 此方法类似于空值,但对于具有默认值的参数,使用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());
      

      可选将方法约定显式地用于调用方,但是,可能会发现这样的签名太冗长。

      更新:Java 8包含类 java.util.Optional 箱外,因此在Java 8中不需要使用番石榴。但是方法名有点不同。

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

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

        3
  •  99
  •   theninjagreg    14 年前

    您可以使用如下内容:

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

    这个 params 变量是可选的。它被视为可以为空的对象数组。

    奇怪的是,我在文档中找不到任何关于这个的信息,但是它是有效的!

    这是爪哇1.5和以后的“新”(不支持Java 1.4或更早的版本)。

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

        4
  •  95
  •   tomloprod    6 年前

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

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

    你可以打电话给 doSomething(); doSomething(true); 现在。

        5
  •  47
  •   Dario    15 年前

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

    void SomeMethod(int age, String name) {
        //
    }
    
    // Overload
    void SomeMethod(int age) {
        SomeMethod(age, "John Doe");
    }
    
        6
  •  47
  •   Scott Stanchfield    15 年前

    不幸的是,Java不直接支持默认参数。

    但是,我已经编写了一组JavaBean注释,其中一个支持如下默认参数:

    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

        7
  •  21
  •   Yishai    15 年前

    已经提到varargs和重载。另一种选择是构建器模式,它看起来像这样:

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

    尽管该模式最适合在构造函数中需要可选参数时使用。

        8
  •  13
  •   az3    12 年前

    在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);
            }
        }
    }
    
        9
  •  8
  •   Dom Hastings    5 年前

    这取决于您想要实现什么,varargs或方法重载应该解决大多数场景。 下面是一些如何使用它们的好例子:

    http://blog.sleekface.com/in/java-core/method-with-optional-parameters/

    但请记住不要过度使用方法重载。这会带来混乱。

        10
  •  6
  •   T.Todua Laurent W.    7 年前

    短版:

    使用 三点 :

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

        11
  •  4
  •   Ishan Fernando    8 年前

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

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

    也可以使用@nullable注释

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

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

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

    public void load(String name...){}
    
        12
  •  2
  •   Jarvis    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提供的变量参数。 这里有一个 link 为了解释。

        13
  •  1
  •   Pellet    7 年前

    Java现在支持OpTales在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
    }
    
        14
  •  1
  •   rybai    7 年前

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

    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() 不接受可选参数的方法。

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

        15
  •  0
  •   Sujay U N    7 年前

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

    |*|方法重载:

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

    最简单的方法是

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

    RetDtaTyp NamFnc(int NamPsgVar, String... SrgOpnPsgVar)
    {
        if(SrgOpnPsgVar.length == 0)  SrgOpnPsgVar = DefSrgVar; 
    
        // |* CodTdo *|
        return RetVar;
    }
    

        16
  •  0
  •   Sebastian    6 年前

    缺省参数不能用于爪哇和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-