Как известно, в Java нет отдельных функций, как в С++/C/PHP/…, все реализуется в пределах класса и бывает случаи, когда необходимо передавать параметры методу или конструкции по умолчанию, или переменное количество параметров. В данной статье рассмотрим несколько способов реализации передачи необязательных параметров.
1.Способ перегрузки
void foo(String a,Integer b){//...} void foo(String a){ foo(a,0);// где, 0 является необязательным параметром для b } foo("a",2); foo("a");
Одним из ограничений такого подхода является то, что он не работает, если у вас есть два необязательных параметра одного и того же типа и любой из них может быть опущен.
2. Использование 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");
Главный недостаток данного подхода — то, что необязательные параметры имеют различные типы и этим вы теряете статическую проверку типов. Кроме того, если каждый параметр имеет различные значения, то необходимо каким-то образом различить их.
3. Проверка на NULL
Для устранения ограничения передачи по типу можно использовать другой подход — проверка на передача значения на null и внутри тела функции организовать проверку : если передано null, то установить значения по умолчанию
void foo(String a,Integer b,Integer c){ b = b !=null? b :0; c = c !=null? c :0; //... } foo("a",null,2);
Теперь все значения всех аргументов должны быть определены, но по умолчанию можно установить и как null.
4. Передача необязательного класса
Этот подход аналогичен предыдущему подходу, но использует guava необязательный класс в виде параметра, который имеет значения по умолчанию
void foo(String a,Optional bOpt){ Integer b = bOpt.isPresent()? bOpt.get():0; //... } foo("a",Optional.of(2)); foo("a",Optional.absent());
5.Использование шаблона Builder
Шаблон Builder используется для конструкторов и реализуется путем введения отдельного класса Builder
class Foo{ privatefinalString a; privatefinalInteger b; Foo(String a,Integer b){ this.a = a; this.b = b; } //... } class FooBuilder{ privateString a =""; privateInteger b =0; FooBuilder setA(String a){ this.a = a; return this; } FooBuilder setB(Integer b){ this.b = b; return this; } Foo build(){returnnewFoo(a, b); } } Foo foo =new FooBuilder().setA("a").build();
6. Использование карт Maps
Когда количество параметров слишком большое и для большинство из них используют значения по умолчанию, то вы можете получить аргументы метода в виде карты, как имя/значение
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 =(String)parameters.get("a"); } if(parameters.containsKey("b")){ //... } //... } foo(ImmutableMap.<String, Object>of("a", "a", "b", 2, "d", "value"));