Дополнительные параметры Java - PullRequest
727 голосов
/ 08 июня 2009

Как использовать дополнительные параметры в Java? Какая спецификация поддерживает необязательные параметры?

Ответы [ 17 ]

1540 голосов
/ 21 октября 2012

Существует несколько способов имитации необязательных параметров в 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);
    

    б) Типы необязательных параметров могут быть разными:

    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 из коробки, поэтому нет необходимости использовать guava по этой конкретной причине в Java 8. Хотя имя метода немного отличается.

  5. Шаблон Builder. Шаблон Builder используется для конструкторов и реализуется путем введения отдельного класса 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 = (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"));
    

Обратите внимание, что вы можете комбинировать любой из этих подходов для достижения желаемого результата.

471 голосов
/ 08 июня 2009

varargs может сделать это (в некотором роде). Кроме этого, все переменные в объявлении метода должны быть предоставлены. Если вы хотите, чтобы переменная была необязательной, вы можете перегрузить метод, используя сигнатуру, которая не требует параметра.

private boolean defaultOptionalFlagValue = true;

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

public void doSomething() {
    doSomething(defaultOptionalFlagValue);
}
100 голосов
/ 04 декабря 2010

Вы можете использовать что-то вроде этого:

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

Переменная params является необязательной. Он рассматривается как обнуляемый массив объектов.

Странно, я ничего не нашел в документации, но это работает!

Это «новый» в Java 1.5 и более поздних версиях (не поддерживается в Java 1.4 или более ранних версиях).

Я вижу, что пользователь bhoot тоже упоминал об этом ниже.

98 голосов
/ 02 апреля 2010

Есть дополнительные параметры с Java 5.0. Просто объявите вашу функцию так:

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

вы можете звонить с doSomething(); или doSomething(true); сейчас.

49 голосов
/ 08 июня 2009

К сожалению, 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

47 голосов
/ 08 июня 2009

В Java нет дополнительных параметров. То, что вы можете сделать, это перегрузить функции и затем передать значения по умолчанию.

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

// Overload
void SomeMethod(int age) {
    SomeMethod(age, "John Doe");
}
21 голосов
/ 08 июня 2009

VarArgs и перегрузка были упомянуты. Другой вариант - это шаблон Builder, который будет выглядеть примерно так:

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

Хотя этот шаблон будет наиболее подходящим для случаев, когда вам нужны дополнительные параметры в конструкторе.

14 голосов
/ 24 августа 2012

В 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);
        }
    }
}
8 голосов
/ 05 декабря 2009

Это будет зависеть от того, чего вы хотите достичь, varargs или перегрузка методов должны решить большинство сценариев. Вот несколько хороших примеров их использования:

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

но имейте в виду, чтобы не использовать перегрузку метода. это приносит путаницу.

6 голосов
/ 15 января 2017

Короткая версия:

Использование три точки :

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)

...