Yöntem aşırı yükleme.
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");
Bu yaklaşımın sınırlamalarından biri, aynı tipte iki isteğe bağlı parametreniz varsa ve bunlardan herhangi biri atlanabilirse işe yaramayacağıdır.
Varargs.
a) İsteğe bağlı tüm parametreler aynı tiptedir:
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) İsteğe bağlı parametre türleri farklı olabilir:
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");
Bu yaklaşımın ana dezavantajı, isteğe bağlı parametreler farklı tipteyse statik tip kontrolünü kaybetmenizdir. Ayrıca, her parametrenin farklı bir anlamı varsa, bunları ayırt etmenin bir yoluna ihtiyacınız vardır.
Boşlara. Önceki yaklaşımların sınırlamalarını gidermek için null değerlere izin verebilir ve ardından bir yöntem gövdesindeki her parametreyi analiz edebilirsiniz:
void foo(String a, Integer b, Integer c) {
b = b != null ? b : 0;
c = c != null ? c : 0;
//...
}
foo("a", null, 2);
Şimdi tüm bağımsız değişken değerleri sağlanmalıdır, ancak varsayılan değerler boş olabilir.
İsteğe bağlı sınıf. Bu yaklaşım null değerlerine benzer, ancak varsayılan değeri olan parametreler için Java 8 Optional sınıfını kullanır:
void foo(String a, Optional<Integer> bOpt) {
Integer b = bOpt.isPresent() ? bOpt.get() : 0;
//...
}
foo("a", Optional.of(2));
foo("a", Optional.<Integer>absent());
İsteğe bağlı bir yöntem sözleşmesini bir arayan için açık hale getirir, ancak böyle bir imza çok ayrıntılı bulabilir.
Oluşturucu desen. Oluşturucu deseni yapıcılar için kullanılır ve ayrı bir Builder sınıfı eklenerek uygulanır:
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();
Haritalar. Parametre sayısı çok fazla olduğunda ve çoğu için varsayılan değerler genellikle kullanıldığında, yöntem bağımsız değişkenlerini adlarının / değerlerinin haritası olarak iletebilirsiniz:
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");
} else if (parameters.containsKey("b")) {
//...
}
//...
}
foo(ImmutableMap.<String, Object>of(
"a", "a",
"b", 2,
"d", "value"));
İstenilen bir sonuç elde etmek için bu yaklaşımlardan herhangi birini birleştirebileceğinizi lütfen unutmayın.