15 Haziran 2022 Çarşamba

Optional Nasıl Kullanılmalı - Optional Method Argument

Giriş
Bu konuyla ilgili aslında tam bir uzlaşma yok. Bazılarına göre bu durum kabul edilebilir.

Taraf 1'in Savunması
Optional method argument olmamalı diyenlerin açıklaması şöyle. Yani "Never use Optional as a method argument" diyenler. Bunlara Taraf 1 diyelim
Optional is not a replacement for null nor a fancy way to prevent NullPointerException. It is to indicate that the question is unanswerable, like: what is the average age of an empty list of persons.

Optionals should never be passed on, but unboxed by the calling code as soon as possible.
Taraf 1'in açıklaması şöyle. Yani null değer istemiyorsak @NonNull kullanarak zaten bunu yakalayabiliriz.
While writing a method it is recommended to annotate the required argument with @NonNull . Since author of the code knows which argument is required and which not . So better to use basic validation and throw exception in case of validation failed.
Bu konuda bir yazı da şöyle
In Java, there's no way to know whether a variable is null. To be explicit, Java 8 introduced the Optional type. From Java 8 onward, returning an Optional implies the underlying value can be null; returning another type implies it cannot.

However, the developers of Optional designed it for return values only. Nothing is available in the language syntax for methods parameters and return values. To cope with this, a bunch of libraries provide compile-time annotations:
NotNull anotasyonu sağlayan bazı kütüphaneler şöyle

Taraf 2'nin Savunması
Optional method argument  olabilir diyenlerin açıklaması şöyle. Bunlara Taraf 2 diyelim.
Passing an Optional result to another method, without any semantic analysis; leaving that to the method, is quite alright.
Optional method argument olmamalı diyenler şöyle kodlar olmamalı diyorlar.
public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {
    // my logic
}
Optional Metod Argument İstemiyorsak

Çözüm 1 - Optional Parametreden Kurtulmak İçin Overload metod kullanmak

Aşağıdaki örneklerde her iki tarafın da haklı olduğu örnekler verdim.

Örnek - Tek parametre null olabiliyorsa
Eğer Optional kullansaydık şöyle yapardık
public SystemMessage(String title, String content, Optional<Attachment> attachment) {
    // assigning field values
}
Taraf 1'e uyarak Optional parametreden kurtulmak için metodumuzu overload ederek şöyle yapalım. Burada Attachment parametresi null olabiliyor.
public SystemMessage(String title, String content) {
    this(title, content, null);
}

public SystemMessage(String title, String content, Attachment attachment) {
    // assigning field values
}
Overload edilen metodun birinci halini çağırmak için şöyle yaparız
SystemMessage withoutAttachment = new SystemMessage("title", "content");
Overload edilen metodun ikinci halini çağırmak için şöyle yaparız
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", attachment);

Örnek - İki parametre null olabiliyorsa
Bu örnekte aslında Optional parametre geçmemenin kodu daha da zorlaştırdığı görülüyor.
Optional kullansaydık şöyle yapardık.
public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {
    // my logic
}
Taraf 1'e uyarak Optional parametreden kurtulmak için metodumuzu overload ederek  şöyle yapalım. Burada null olabilecek parametreler için metod overload ediliyor.
public int calculateSomething() {
    calculateSomething(null, null);
}

public int calculateSomething(String p1) {
    calculateSomething(p1, null);
}

public int calculateSomething(BigDecimal p2) {
    calculateSomething(null, p2);
}

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}
Bu durumda kodu çağırmak için şöyle yaparız. Görüldüğü gibi kod daha karmaşık hale gelmeye başladı
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result;
if (p1.isPresent()) {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p1, p2);
    } else {
        result = myObject.calculateSomething(p1);
    }
} else {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p2);
    } else {
        result = myObject.calculateSomething();
    }
}
Çözüm 2 - Optional Parametreden Kurtulmak İçin Metod Çağrısında Optional.orElse Kullanmak
Örnek
Metodumuzdaki Optional parametreleri kaldırarak şöyle yaparız. Metoda null parametre gelecekmiş gibi kabul edip, kontrol etmek gerekir.
public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}
Bu durumda kullanmak için şöyle yaparız.
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));
Örnek
Elimizde şöyle bir kod olsun
public void doAction() {
  OptionalInt age = getAge();
  Optional<Role> role = getRole();
  applySettings(name, age, role);
}
Metod imzasında Optional parametre kullanmamaya karar verdiysek şöyle yaparız. Burada default değerler kullanılıyor.
public void doAction() {
OptionalInt age = getAge(); Optional<Role> role = getRole(); applySettings(name, age.orElse(defaultAge), role.orElse(defaultRole)); }



Hiç yorum yok:

Yorum Gönder