ว่าด้วยเรื่อง “Optional” ใน Java

Phayao Boonon
4 min readJan 22, 2019

--

ใน Java 8 ได้มีคลาสใหม่ที่ชื่อว่า Optional ใน java.util ซึ่งเป็นคลาสที่เอามาใช้แทนค่าที่ “มีอยู่” หรือ “ไม่มีอยู่” หรือค่า NULL นั้นเอง จุดประสงค์หลักของคลาสนี้คือใช้ค่า optional แทนที่จะอ้างอิง null เพื่อแก้ปัญหา NullPointerException

https://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html

ตัวอย่างเช่น เราประกาศตัวแปรอ้างอิง (reference variable) แต่ไม่ได้กำหนดค่าอ้างอิงให้หรือค่าตั้งต้นเป็น null เมื่อเราใช้งาน method ของตัวแปรนี้จะได้ error เป็น java.lang.NullPointerException

public class Demo {
public static void main(String[] args) {
String hello = null;
hello.length();
}
}
Output:
Exception in thread "main" java.lang.NullPointerException

ดังนั้นคลาส Optional จะมาช่วยแก้ปัญหานี้ โดยที่ Optional จะห่อหุ่ม (wrapper) object ที่เราต้องการและสามารถดำเนินการต่างๆ กับ object นั้นได้

Creating Optional object

เราสามารถสร้าง Optional object ได้กลายวิธี เริ่มด้วยการสร้าง Optional ว่างเปล่าด้วย method empty() จะได้ Optional.empty

public class Demo {
public static void main(String[] args) {
Optional<String> opt = Optional.empty();
System.out.println(opt);
}
}
Output:
Optional.empty

สามารถสร้าง Optional object ที่มีค่าด้วย method of(T value) ซึ่งจะได้ Optional object ของ value นั้นๆ

public class Demo {
public static void main(String[] args) {
Optional<String> opt = Optional.of("Hello");
System.out.println(opt);
}
}
output:
Optional[Hello]

แต่ถ้าเราไม่แน่ใจว่าค่าที่เราจะสร้างด้วย Optional นั้นเป็นค่าว่างเปล่าหรือ null หรือไม่ สามารถใช้ method ofNullable(T value)

public class Demo {
public static void main(String[] args) {
Optional<String> opt;
opt = Optional.ofNullable(null);
System.out.println(opt);

opt = Optional.ofNullable("Hello");
System.out.println(opt);
}
}
output:
Optional.empty
Optional[Hello]

จะเห็นได้ว่าเราสามารถใช้ ofNullable สร้าง Optional object จากค่าที่เป็น null หรือ ค่าที่มีค่า ถ้าค่าเป็น null จะได้ Optional.empty แต่ถ้าค่ามีค่าจะได้ Optional ของค่านั้นๆ

Checking Value

เมื่อสร้าง Optional object แล้วสามารถตรวจสอบการมีอยู่ของค่าที่อยู่ใน Optional object ได้ด้วย method isPresent()

public class Demo {
public static void main(String[] args) {
Optional<String> opt;
opt = Optional.ofNullable(null);
System.out.println(opt.isPresent());

opt = Optional.ofNullable("Hello");
System.out.println(opt.isPresent());
}
}
output:
false
true

หรือในทางกลับกันใช้ methodisEmpty() (ใน Java 11 เท่านั้น)

public class Demo {
public static void main(String[] args) {
Optional<String> opt;
opt = Optional.ofNullable(null);
System.out.println(opt.isEmpty());

opt = Optional.ofNullable("Hello");
System.out.println(opt.isEmpty());
}
}
output:
true
false

Conditional Action

เราสามารถตรวจสอบเงื่อนไขและดำเนินการบางอย่างกับ Optional object ได้ด้วย method ifPresent() โดยที่จะดำเนินการก็ต่อเมื่อ Optional นั้นมีค่าแต่ถ้าไม่มีค่าก็จะไม่ทำอะไร

public class Demo {
public static void main(String[] args) {
Optional<String> opt = Optional.ofNullable("Hello");

opt.ifPresent(c -> System.out.println(c.length()));
}
}
output:
5

จากตัวอย่างจะเห็นได้ว่าจะดำเนินการ print ขนาดของ String ออกมาถ้า Optional opt มีค่า

ใน Java 9 ได้เพิ่ม method ifPersentOrElse() เพื่อเพิ่มเติมจัดการเงื่อนไขถ้า Optional ไม่มีค่า ด้วย Runnable action

public class Demo {
public static void main(String[] args) {
Optional<String> opt = Optional.empty();

opt.ifPresentOrElse(c -> System.out.println(c.length()),
() -> System.out.println("Other"));
}
}
output:
Other

Return Value

เมื่อห่อหุ่มค่าต่างๆ ด้วย Optional แล้ว จะเอาค่านั้นออกมาได้ด้วย method get()

public class Demo {
public static void main(String[] args) {
Optional<String> opt = Optional.ofNullable("Hello");
System.out.println(opt.get());
}
}
output:
Hello

Default Value

ถ้าเราใช้ method get() เพื่อเอาค่าของ Optional object ออกมา แต่ถ้าค่านั้นเป็น null ก็จะไม่ต่างอะไรจากไม่ใช้ Optional แต่เราสามารถกำหนดค่าเริ่มต้นให้ถ้าเจอค่าเป็น null ด้วย method orElse(T other)

public class Demo {
public static void main(String[] args) {
Optional<String> opt = Optional.ofNullable(null);
System.out.println(opt.orElse("Hello"));
}
}
output:
Hello

หรือเราสามรถดำเนินการอย่างอื่นนอกเหนือจาก return ค่ากลับเฉยๆ ด้วย method orElseGet()

public class Demo {
public static void main(String[] args) {
Optional<String> opt = Optional.ofNullable(null);
System.out.println(opt.orElseGet(() -> "Hello"));
}
}
output:
Hello

ใน Java 9 ได้เพิ่ม method or() ขึ้นมาเพื่อดำเนินการและ return ค่าเป็น Optional สำหรับ Optoinal ที่มีค่าจะ return เป็นค่าเดิม

public class Demo {
public static void main(String[] args) {
Optional<String> opt = Optional.ofNullable("Hello");
Optional<String> defaultOpt = Optional.of("Default");

System.out.println(opt.or(() -> defaultOpt));
}
}
output:
Optional[Hello]

สำหรับ Optional ที่ไม่มีค่า จะ return เป็นค่าใน or() statement

public class Demo {
public static void main(String[] args) {
Optional<String> opt = Optional.empty();
Optional<String> defaultOpt = Optional.of("Default");

System.out.println(opt.or(() -> defaultOpt));
}
}
output:
Optional[Default]

Exception

ถ้าเราไม่ต้องการจะ return หรือว่าดำเนินการอะไรหลังจากตรวจสอบว่าค่าเป็น null สามารถ throw Exception ออกมาได้เช่นกัน

public class Demo {
public static void main(String[] args) {
Optional<String> opt = Optional.ofNullable(null);
opt.orElseThrow(IllegalArgumentException::new);
}
}
output:
java.lang.IllegalArgumentException

Conditional Return

เราสามารถตรวจสอบค่าที่ return ของ Optional object ได้ด้วย method filter() โดยใช้เพื่อแยกค่าที่เราต้องการและเอาค่าที่เราไม่ต้องการออกไปด้วยเงื่อนไข

public class Demo {
public static void main(String[] args) {
boolean present;
Optional<String> opt = Optional.ofNullable("Hello");

present = opt.filter(c -> c == "Hello").isPresent();
System.out.println(present);

present = opt.filter(c -> c == "Other").isPresent();
System.out.println(present);
}
}
output:
true
false

Transforming Value

เราสามารถเปลี่ยนแปลงค่าใน Optional object ที่มีค่าได้ด้วย method map()

public class Demo {
public static void main(String[] args) {
Optional<String> opt = Optional.ofNullable("Hello");
System.out.println(opt.map(String::toUpperCase).get());
}
}
output:
HELLO

แต่ก็มี method flatMap() ที่คล้าย map() แต่ใช้ดำเนินการกับค่าที่เป็น Optional

public class Demo {
public static void main(String[] args) {
Optional<String> opt = Optional.ofNullable("Hello");
Optional<Optional<String>> optOfOpt = Optional.of(opt);

System.out.println(optOfOpt.flatMap(
c -> c.map(String::toUpperCase)).get());
}
}
output:
HELLO

Stream

ใน Java 9 สามารถแปลง Optional object ไปเป็น Stream ได้และสามาถดำเนินการในแบบ Stream ได้เลย

public class Demo {
public static void main(String[] args) {
Optional<String> opt = Optional.ofNullable("Hello");

System.out.println(opt.stream().map(String::toUpperCase)
.collect(Collectors.toList()));

}
}
output:
[HELLO]

--

--

Phayao Boonon

Software Engineer 👨🏻‍💻 Stay Hungry Stay Foolish