Tóm Tắt
Java 8 Tutorial: Optional
Optional là 1 container được giới thiệu trong Java 8, theo quảng cáo của Oracle thì nó sẽ giúp cho các lập trình viên tránh được cơn ác mộng NullPointerException. Nhưng theo mình thấy thì thay vì kiểm tra null bằng cách thông thường, Optional cung cấp 1 số hàm, tiện ích khác để chúng ta check null. Mình cũng chưa có cơ hội áp dụng vào thực tế, nhưng trước hết, cùng điểm qua 1 số hàm mà Optional cung cấp.
Optional chính xác là gì
Theo Javadoc của Java 8 định nghĩa thì:
Optional là một class nằm trong gói java.util, nó là 1 object container có thể đang chứa một object thực hoặc một giá trị null. Bằng việc sử dụng hàm isPresent có thể check được object được chứa trong nó là null hay không, và hàm get để get ra object đó.
empty Tạo ra 1 empty Optional // Create an empty Optional Optional emptyOptional = Optional.empty();
of
Hàm of nhận vào 1 đối tượng non-null và trả về một đối tượng Optional chứa đối tượng đó. Nếu truyền vào hàm of 1 đối tượng null, chúng ta nhận về 1 NullPointerException
// Create Optional object which contains a String object Optional name = Optional.of("Edward"); // It will throw NullPointerException Optional nullName = Optional.of(null);
ofNullable
Tương tự như of, nhưng trong trường hợp hàm nhận vào 1 null object, nó sẽ trả về 1 Empty Optional thay vì throw NullPointerException
// Return an empty Optional Optional empty = Optional.ofNullable(null); // Simply check it. true System.out.println(empty.equals(emptyOptional));
isPresent
Trả về true trong trường hợp object đang tồn tại. Ngược lại là false
// true System.out.println(name.isPresent()); // false System.out.println(emptyOptional.isPresent());
get
Trả về object nếu đang tồn tại trong Optional. Ngược lại throw NoSuchElementException
// Edward System.out.println(name.get()); // It will throw NoSuchElementException System.out.println(emptyOptional.get());
ifPresent
Hàm nhận vào 1 Consumer. Nếu object đang tồn tại sẽ chạy đoạn mã thực thi của Consumer, ngược lại sẽ không làm gì cả. Có thể hiểu nó là 1 Functional Interface nhận vào 1 tham số, không có giá trị trả về.
// Hello Edward name.ifPresent((value) -> System.out.println("Hello " + value)); // Nothing happens emptyOptional.ifPresent((value) -> System.out.println("Hello " + value));
orElse
Trả về object nếu đang tồn tại, ngược lại trả về giá trị mặc định do Client định nghĩa
// Edward System.out.println(name.orElse("NoName")); // NoName System.out.println(emptyOptional.orElse("NoName"));
orElseGet
Phương thức này tương tự như phương thức orElse ở trên. Nhưng trong trường hợp object không tồn tại, nó sẽ dùng 1 Supplier interface để tạo ra giá trị mặc định. Supplier có thể được hiểu như một Functional Interface không nhận vào tham số nào, và có kiểu trả về.
// Edward System.out.println(name.orElseGet(() -> {return "NoName";})); // NoName System.out.println(emptyOptional.orElseGet(() -> {return "NoName";}));
orElseThrow
Cũng tương tự như 2 phương thức orElse và orElseGet. Nhưng trong trường hợp object không tồn tại, sẽ throw ra Exception từ lambda expression do Client tự định nghĩa.
// Edward try { System.out.println(name.orElseThrow(() -> {return new Exception();})); // Lambda expression } catch (Exception e) { e.printStackTrace(); } // Cannot get object from emptyOptional try { // It will throw Exception System.out.println(emptyOptional.orElseThrow(Exception::new)); // Here is also lambda expression, both are the same } catch (Exception e) { // Catch it System.out.println("Cannot get object from emptyOptional"); e.printStackTrace(); }
map
Trong trường hợp object đang tồn tại, sử dụng lambda expression với đối số là object đó và tạo ra 1 Optional mới chứa object chính là kết quả trả về từ lambda expression. Ngược lại, trả về 1 empty Optional
Optional upperName = name.map((value) -> {return value.toUpperCase();}); // EDWARD upperName.ifPresent((value) -> {System.out.println(value);}); Optional lowerName = emptyOptional.map((value) -> {return value.toUpperCase();}); // Nothing happens lowerName.ifPresent((value) -> {System.out.println(value);});
flatMap
Phương thức này cũng nhận vào 1 lambda expression giống như phương thức map. Nhưng kết quả trả về từ lambda expression luôn là 1 Optional
// EDWARD Optional upperName2 = name.flatMap((value) -> Optional.of(value.toUpperCase())); System.out.println(upperName2.orElse("NoName")); Optional lowerName2 = emptyOptional.map((value) -> {return value.toUpperCase();}); // NoName System.out.println(lowerName2.orElse("NoName"));
filter
Phương thức này truyền vào 1 lambda expresison thực thi cho Predicate interface như là một điều kiện kiểm tra. Nếu object đang chứa trong Optional không thỏa mãn sẽ trả về một empty Optional, ngược lại trả về một Optional mới chứa object đó.
Optional validName = name.filter((value) -> {return value.length() > 3;}); // Edward is valid validName.ifPresent((value) -> {System.out.println(value + " is valid");}); Optional validName1 = name.filter((value) -> {return value.length() > 10;}); // Nothing happens validName1.ifPresent((value) -> {System.out.println(value + " is valid");});
Các bạn có thể xem full source code ở đây:
import java.util.Optional; public class Optional1 { public static void main(String[] args) { // empty // Create an empty Optional Optional emptyOptional = Optional.empty(); // of // Create Optional object which contains a String object Optional name = Optional.of("Edward"); try { // It will throw NullPointerException Optional nullName = Optional.of(null); } catch(Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } // ofNullable // Return an empty Optional Optional empty = Optional.ofNullable(null); // Simply check it. true System.out.println(empty.equals(Optional.empty())); // isPresent // true System.out.println(name.isPresent()); // false System.out.println(emptyOptional.isPresent()); // get // Edward System.out.println(name.get()); try { // It will throw NoSuchElementException System.out.println(emptyOptional.get()); } catch(Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } // ifPresent // Hello Edward name.ifPresent((value) -> System.out.println("Hello " + value)); // Nothing happens emptyOptional.ifPresent((value) -> System.out.println("Hello " + value)); // orElse // Edward System.out.println(name.orElse("NoName")); // NoName System.out.println(emptyOptional.orElse("NoName")); // orElseGet // Edward System.out.println(name.orElseGet(() -> {return "NoName";})); // NoName System.out.println(emptyOptional.orElseGet(() -> {return "NoName";})); // orElseThrow // Edward try { System.out.println(name.orElseThrow(() -> {return new Exception();})); // Lambda expression } catch (Exception e) { e.printStackTrace(); } // Cannot get object from emptyOptional try { // It will throw Exception System.out.println(emptyOptional.orElseThrow(Exception::new)); // Here is also lambda expression, both are the same } catch (Exception e) { // Catch it System.out.println("Cannot get object from emptyOptional"); e.printStackTrace(); } // map Optional upperName = name.map((value) -> {return value.toUpperCase();}); // EDWARD upperName.ifPresent((value) -> {System.out.println(value);}); Optional lowerName = emptyOptional.map((value) -> {return value.toUpperCase();}); // Nothing happens lowerName.ifPresent((value) -> {System.out.println(value);}); // flatMap // EDWARD Optional upperName2 = name.flatMap((value) -> Optional.of(value.toUpperCase())); System.out.println(upperName2.orElse("NoName")); Optional lowerName2 = emptyOptional.map((value) -> {return value.toUpperCase();}); // NoName System.out.println(lowerName2.orElse("NoName")); // filter Optional validName = name.filter((value) -> {return value.length() > 3;}); // Edward is valid validName.ifPresent((value) -> {System.out.println(value + " is valid");}); Optional validName1 = name.filter((value) -> {return value.length() > 10;}); // Nothing happens validName1.ifPresent((value) -> {System.out.println(value + " is valid");}); } }
Kết quả:
null java.lang.NullPointerException at java.util.Objects.requireNonNull(Unknown Source) at java.util.Optional.(Unknown Source) at java.util.Optional.of(Unknown Source) at com.edward.tutorial.java8.optional.Optional1.main(Optional1.java:17) true true false Edward No value present java.util.NoSuchElementException: No value present at java.util.Optional.get(Unknown Source) at com.edward.tutorial.java8.optional.Optional1.main(Optional1.java:41) Hello Edward Edward NoName Edward NoName Edward Cannot get object from emptyOptional java.lang.Exception at com.edward.tutorial.java8.optional.Optional1$$Lambda$6/798154996.get(Unknown Source) at java.util.Optional.orElseThrow(Unknown Source) at com.edward.tutorial.java8.optional.Optional1.main(Optional1.java:76) EDWARD EDWARD NoName Edward is valid
Kết thúc bài giới thiệu về Optional trong Java 8 tại đây. Mình rất vui nếu có thể nhận được các đóng góp các ý kiến phản hồi bằng cách comment bên dưới bài viết. Các bạn có thể tham khảo một số bài viết khác trong series Java 8 Tutorial tại đây:
Series Java Core Overview
http://www.edwardthienhoang.wordpress.com
Share this:
Like this:
Like
Loading…