Дополнительные параметры 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.