Необязательные параметры в Java
Как использовать дополнительные параметры в Java? Какая спецификация поддерживает дополнительные параметры?
16 ответов
varargs может сделать это (в некотором роде). Кроме этого, необходимо указать все переменные в объявлении метода. Если вы хотите, чтобы переменная была необязательной, вы можете перегрузить метод, используя подпись, которая не требует параметра.
private boolean defaultOptionalFlagValue = true;
public void doSomething(boolean optionalFlag) {
...
}
public void doSomething() {
doSomething(defaultOptionalFlagValue);
}
существует несколько способов моделирования необязательных параметров в 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.
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");
основным недостатком этого подхода является то, что если необязательные параметры имеют разные типы, вы теряете статическую проверку типа. Кроме того, если каждый параметр имеет разное значение, вам нужно каким-то образом их различать.
-
Nulls. чтобы устранить ограничения предыдущих подходов, вы можете разрешить нулевые значения, а затем проанализировать каждый параметр в теле метода:
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());
необязательно делает контракт метода явным для вызывающего абонента, однако можно найти такую подпись слишком многословной.
обновление: Java 8 включает класс
java.util.Optional
из коробки, поэтому никакая потребность использовать гуава для этой цели в Java 8. Однако имя метода немного отличается. -
шаблон строителя. шаблон 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();
-
карты. когда количество параметров слишком велико и для большинства из них обычно используются значения по умолчанию, вы можете передать аргументы метода в виде карты их имена/значения:
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"));
обратите внимание, что вы можете комбинировать любой из этих подходов, чтобы добиться желаемого результата.
Вы можете использовать что-то вроде этого:
public void addError(String path, String key, Object... params) {
}
на params
переменной не является обязательным. Он рассматривается как nullable массив объектов.
странно, я ничего не мог найти об этом в документации, но он работает!
Это "новое" в Java 1.5 и выше (не поддерживается в Java 1.4 или более ранней версии).
Я вижу, что пользователь bhoot упомянул об этом ниже.
есть дополнительные параметры с Java 5.0. Просто объявите свою функцию следующим образом:
public void doSomething(boolean... optionalFlag) {
//default to "false"
//boolean flag = (optionalFlag.length >= 1) ? optionalFlag[0] : false;
}
вы можете позвонить с doSomething();
или doSomething(true);
сейчас.
к сожалению, 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
в Java нет дополнительных параметров. Вы можете перегрузить функции, а затем передать значения по умолчанию.
void SomeMethod(int age, String name) {
//
}
// Overload
void SomeMethod(int age) {
SomeMethod(age, "John Doe");
}
были упомянуты VarArgs и перегрузка. Другой вариант шаблона, который будет выглядеть примерно так:
MyObject my = new MyObjectBuilder().setParam1(value)
.setParam3(otherValue)
.setParam6(thirdValue)
.build();
хотя этот шаблон будет наиболее подходящим для того, когда вам нужны дополнительные параметры в конструкторе.
в 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);
}
}
}
Это будет зависеть от того, чего вы хотите достичь, varargs или перегрузка метода должны решить большинство сценариев.
но имейте в виду, чтобы не перегружать метод использования. это приводит в замешательство.
короткая версия :
используя три точки:
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)
вы можете сделать это, используя метод перегрузки, как это.
public void load(String name){ }
public void load(String name,int age){}
также вы можете использовать аннотацию @нам!--4-->
public void load(@Nullable String name,int age){}
просто передать null в качестве первого параметра.
Если вы передаете переменную того же типа, вы можете использовать это
public void load(String name...){}
перегрузка в порядке, но если есть много переменных, которым нужно значение по умолчанию, вы получите :
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. Вот ссылке для объяснения.
Java теперь поддерживает optionals в 1.8, я застрял с программированием на android, поэтому я использую nulls, пока не смогу рефакторировать код для использования дополнительных типов.
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 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.
аргументы по умолчанию не могут использоваться в Java и C#. Где в C++ и Python мы можем их использовать..
в Java, мы должны использовать 2 метода (функции), а не с параметрами по умолчанию.
пример:
Stash(int size);
Stash(int size, int initQuantity);
мы можем сделать необязательный параметр методом перегрузки или с помощью типа данных...
|*| перегрузка метода :
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;
}