Дополнительные параметры Java


813

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

Ответы:


517

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

private boolean defaultOptionalFlagValue = true;

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

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

На мой взгляд, перегрузка методов - хороший ответ, а varargs - очень плохой. Пожалуйста, удалите комментарий к varargs или объясните серьезный недостаток, вызванный возможностью более чем одного возвращаемого значения.
Андреас

Добавление глобальных переменных может вызвать некоторые другие проблемы.
Хелен Цуй

1654

Есть несколько способов симулировать необязательные параметры в 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. С переменным числом аргументов.

    а) Все необязательные параметры имеют одинаковый тип:

    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:

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

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


2
@Vitalii Fedorenko Хм, я думаю, что вы допустили небольшую ошибку копирования-вставки в # 6: вы проверяете тип для Integer, хотя ваша aпеременная является String (приведение правильное).
Неизвестный Id

5
@ Aetos твоя ссылка мертва.
Робиньо

2
@Robino альтернативная ссылка утверждая , что Факультативный не следует использовать в качестве параметра здесь . Несмотря на использование в Optionalкачестве параметра в одном из вариантов, этот ответ очень хорош.
Дерик

Наиболее распространенным решением вышеуказанной проблемы является, вероятно, перегрузка метода. Хотя я никогда не был фанатом этого. Лично я предпочел бы, если бы они добавили какой-то идентификатор для параметров конфигурации.
Александр Хейм

1
это должен быть, вероятно, лучший ответ - охватывает все
xproph

104

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

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

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


13
Это на самом деле правильный ответ. Это просто и компактно. Просто помните, что вы можете получить более одного параметра, поэтому Java помещает их в массив. Например, чтобы получить один параметр, вы должны сначала проверить содержимое массива: «код» логический флаг = (optionFlag.length <1)? False: optionFlag [0];
Сальвадор Валенсия

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

2
Этот способ работает, если у вас есть только один необязательный параметр, но вам нужно проверить длину массива и т. Д., Чтобы он не был супер чистым: | Если вам нужен необязательный параметр «один параметр», то вы также можете просто объявить два метода (один перегружен, doSomething() { doSomething(true); }нет массивов для обработки, нет двусмысленности
rogerdpack

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

Как заметил @sleske, использование varargs имеет ужасный недостаток - разрешается передавать более одного значения. ОП четко спросил о решении для «необязательно», что означает либо одно значение, либо ноль. Как это можно считать хорошим ответом для некоторых, уже давно.
Андреас

99

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

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

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

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

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

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


55

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


53

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

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

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

23

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

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

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


я хочу добавить зависимость параметра для этого. скажем, я хочу установить param3, только если я установил param1. Например, Я хочу установить сообщение о прогрессе, только если я установил прогресс видимым. isProgressVisible (). setProgressMessage («загрузка»). как я могу этого достичь?
Харшал Бхатт

14

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

7

Вы можете сделать это с помощью перегрузки метода, как это.

 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...){}

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

(по ответу @ Виталия Федоренко)


2

Перегрузка хороша, но если есть много переменных, которым нужно значение по умолчанию, вы получите:

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. Вот ссылка для объяснения.


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

2
Еще хуже практиковать - оправдывать недостатки Java и обвинять других в плохой практике, замечая эти неудобства и разрабатывая обходные пути.
BrianO

1
Пожалуйста, добавьте всю необходимую информацию к своему ответу вместо ссылок на внешние источники - данная ссылка не работает
Nico Haase

2

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

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. Этот подход был бы еще лучше, если бы вы могли использовать аннотации и генерацию кода для создания класса Options.


1

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

Object canBeNull() {
    if (blah) {
        return new Object();
    } else {
        return null;
    }
}

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

Можете ли вы привести пример, пожалуйста?
Sepehr

1

Аргументы по умолчанию не могут быть использованы в Java. Где в 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-


28
Более новые версии C # допускают параметры по умолчанию.
Соггер

2
Java также имеет опцию «...» для любого параметра.
Cacho Santa

0

Это старый вопрос, может быть, даже до того, как был введен фактический тип Optional, но в наши дни вы можете рассмотреть несколько вещей: - использовать перегрузку метода - использовать тип Optional, который имеет преимущество в том, чтобы избежать передачи NULL вокруг типа Optional, который был введен в Java 8 до того, как его обычно использовали из сторонних библиотек, таких как Google Guava. Использование необязательных параметров / параметров может рассматриваться как чрезмерное использование, поскольку основной целью было использовать его как время возврата.

Ссылка: https://itcodehub.blogspot.com/2019/06/using-optional-type-in-java.html


0

Мы можем сделать необязательный параметр перегрузкой метода или использованием DataType ...

| * | Метод перегрузки:

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

Самый простой способ

| * | DataType ... может быть необязательным параметром

RetDataType NameFnc(int NamePsgVar, String... stringOpnPsgVar)
{
    if(stringOpnPsgVar.length == 0)  stringOpnPsgVar = DefaultValue; 

    // |* Code Todo *|
    return RetVar;
}


8
RetDtaTyp... шутки в сторону? Является RetDataTypeслишком трудно впечатать?
Александр - Восстановить Монику

Можете ли вы добавить больше объяснений к этому коду? Что делают все эти странные переменные?
Нико

Изменены имена переменных для простоты понимания ...
Суджай ООН

0

Если вы планируете использовать интерфейс с несколькими параметрами , можно использовать следующий структурный шаблон и применить или применить отмену - метод, основанный на ваших требованиях .

public abstract class Invoker<T> {
    public T apply() {
        return apply(null);
    }
    public abstract T apply(Object... params);
}

0

Если это конечная точка API, элегантный способ - использовать аннотации Spring:

@GetMapping("/api/foos")
@ResponseBody
public String getFoos(@RequestParam(required = false, defaultValue = "hello") String id) { 
    return innerFunc(id);
}

Обратите внимание, что в этом случае для innerFunc потребуется переменная, и, поскольку она не является конечной точкой API, нельзя использовать эту аннотацию Spring, чтобы сделать ее необязательной. Ссылка: https://www.baeldung.com/spring-request-param

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.