Java

Java 8 Tutorial: Trọn bộ Java 8 new features từ Pluralsight

Giới thiệu

Blog_Green-Board

Hôm nay mình sẽ share một bộ video Trọn bộ Java 8 new features từ Pluralsight . Với hơn 4 giờ học, các bạn sẽ nắm được tất cả những đặc điểm nổi bật nhất trong Java 8 như Lambda Expression, Stream, Date and Time API, …

This course covers the most useful parts of Java 8. This update of the Java platform is the biggest of all. It’s even bigger than Java 5 that saw the introduction of generics. We’ll begin with lambda expressions and the Stream API, which bring new fundamental patterns to the Java platform. Many problems solved with the Iterator pattern are now solved much more efficiently with the patterns brought by the Stream API. But Java 8 is not only about lambdas, streams and collectors, there is also a new Java Date and Time API which are covered in this course. This API fixes all the flaws of the previous Date/Calendar API and brings new, very useful, concepts and tools. Many new features that bring a functional programming approach have been added to the Collection API. This is also covered in detail. Many more things are covered; little things, scattered here and there in the JDK, like this new StringJoiner class, useful to join strings with a prefix, a postfix, and a separator. JavaFX and Nashorn are also quickly covered, to show the FXML way to describe Graphical User Interfaces, and the new ways to describe JavaFX in Javascript using Nashorn.

 

Download

Link GoogleDrivehttps://drive.google.com/folderview?id=0B5U6Rykwg1bVd3BvMFZoWGViZnM&usp=sharing

Nội dung chi tiết

Introduction to Lambda Expressions in Java 8

  • Introduction, Targeted Audience
  • Module Outline
  • The FileFilter Example
  • A First Lambda Expression
  • Live Coding: A First Lambda Expression
  • Live Coding: Runnable and Comparator Examples
  • Several Ways of Writing Lambda Expressions
  • Three Questions About Lambda Expressions
  • Functional Interfaces
  • Is a Lambda Expression an Object?
  • The Functional Interfaces Toolbox
  • Method References
  • Processing Collections With Lambdas
  • Changing the Way Interfaces Work?
  • Default and Static Methods in Java 8 Interfaces
  • New Patterns: The Predicate Interface Example
  • Live Coding: New Patterns Examples
  • Module Wrap Up

Java 8 Stream API and Collectors

  • Introduction, Module Outline
  • The Map / Filter / Reduce Algorithm
  • What Is a Stream?
  • Definition of a Stream in Java 8
  • Building and Consuming a Stream
  • Filtering a Stream
  • Live Coding: Consuming and Filtering a Stream
  • Lazy Operations on a Stream
  • Lice Coding: Intermediary and Terminal Operations
  • Wrapping up Intermediary and Terminal Operations
  • The Map Operation
  • The Flatmap Operation
  • Lice Coding: Map and Flatmap Examples
  • Wrapping Up Map and Filter on a Stream
  • Reduction, Functions, and Bifunctions
  • Reduction of the Empty Set: Identity Element
  • Optionals
  • Pattern for the Optionals
  • Wrapping Up Reduction Operations
  • Terminal Operations
  • Live Coding: Reductions, Optionals
  • Wrapping Up Operations and Optionals
  • Collectors, Collecting in a String, in a List
  • Collecting in a Map
  • Live Coding: Processing Streams
  • Wrapping Module

Java 8 Date and Time API

  • Introduction and Outline
  • The Old java.util.Date API
  • Why Does Immutability Matter?
  • The Instant Class and the Duration Class
  • The LocalDate Class and the Period Class
  • Live Coding: Local Dates and Periods Examples and Corner Cases
  • Computing Dates From Other Dates
  • The LocalTime Class
  • Dealing With Time Zones: The ZonedTime Class
  • Printing Dates and Times: The DateTimeFormatter
  • From Legacy Code to the New Date and Time API
  • Conclusion and Wrap-Up

Strings, IO, and Other Bits and Pieces

  • Introduction and Outline
  • Strings and StringJoiner
  • Java I/O: Reading Text Files
  • Java I/O: Exploring Directories
  • New Methods on Iterable, Collection, and List
  • Comparator: Patterns and Utilities
  • Numbers, Method References, and Hashcodes
  • Map: Enhancements of Existing Methods
  • Map: The Compute and Merge Methods
  • Live Coding: General Map Enhancements
  • Live Coding: Map Merging
  • Live Coding: Building Bimaps
  • Annotations
  • Conclusion and Wrap Up

Introduction to Java FX 8

  • Introduction and Outline
  • First Key Concepts on a Simple Example
  • Live Coding a Hello World Example
  • Setting Up an Interface Using the JavaFX API
  • Setting Up an Interface Using the FXML File
  • Controller and Dependency Injection
  • Live Coding: Setting Up a UI With FXML and Java Controllers
  • Conclusion and Wrap Up

Nashorn: A JavaScript Engine on the JVM

  • Introduction and Outline
  • jjs: The Nashorn REPL
  • Livecoding: The REPL in Action
  • Running Javascript in Java Classes
  • Writing and Launching JavaFX UI in Javascript
  • Live Coding: JavaFX With Nashorn
  • Conclusion and Wrap Up

Email: edwardthienhoang@gmail.com

http://www.edwardthienhoang.wordpress.com

Java

Java 8 Tutorial: Lambda expression and Streams in Java 8

java8lambda

Giới thiệu

Hôm nay mình sẽ share một bộ video học Java 8 từ LiveLessions. Với hơn 3 giờ học, các bạn sẽ nắm được những đặc điểm nổi bật nhất trong Java 8 là Lambda Expression và Stream.

Tóm tắt nội dung

  • Cách sử dụng những đặc điểm quan trọng nhất trong Java 8: Lambda Expressions và Streams.
  • Những kỹ thuật sử dụng lambda expression: method references, lambda building blocks in the java.util.function package, effectively-final local variables, the @FunctionalInterface annotation, and higher-order functions.
  • Các method mới liên quan đến Stream: forEach, map, filter, reduce, etc.
  • Infinite (unbounded) streams
  • Parallel streams.
  • Lazy evaluation and short-circuit stream operations.
  • Những đặc điểm khác trong Java 8: Functional Interface và Optional class.

Video

Bộ video này được upload trên Youtube bởi bạn Tiep Phan, mình xin mạn phép chia sẻ lại.

Nội dung chi tiết

Introduction

  • Introduction to Java 8: Lambda Expressions and Streams LiveLessons

Lesson 1: Java 8: Installation, Setup, and Review of Supporting Topics

  • Learning objectives
  • 1.1 Getting Started with Java 8
  • 1.2 Java 8 References
  • 1.3 Quick Review of Pre-Lambda Handlers
  • 1.4 Quick Review of Building Generic Methods and Classes
  • 1.5 Wrap-Up

Lesson 2: Lambda Expressions Part 1 – Basics

  • Learning objectives
  • 2.1 Motivation and Overview
  • 2.2 Lambdas: Most Basic Form
  • 2.3 Type Inferencing
  • 2.4 Expression for Body: Implied Return Values
  • 2.5 Comparing Java and JavaScript Sorting
  • 2.6 Omitting Parens for One-Arg Lambdas
  • 2.7 Using Effectively Final Local Variables
  • 2.8 The @FunctionalInterface Annotation
  • 2.9 Method References
  • 2.10 The java.util.function Package
  • 2.11 Final Example
  • 2.12 Wrap-Up

Lesson 3: Lambda Expressions Part 2 – Lambda Building Blocks in java.util.function

  • Learning objectives
  • 3.1 Lambda Building Blocks in java.util.function: Overview
  • 3.2 Predicate
  • 3.3 Function and BiFunction
  • 3.4 Consumer
  • 3.5 Supplier
  • 3.6 BinaryOperator
  • 3.7 Wrap-Up

Lesson 4: Lambda Expressions Part 3

  • Learning objectives
  • 4.1 Variable Scoping
  • 4.2 Method References: Details
  • 4.3 Java 8 Interfaces: Default Methods and Static Methods
  • 4.4 Methods that Return Lambdas
  • 4.5 Wrap-Up

Lesson 5: Streams Part 1

  • Learning objectives
  • 5.1 Overview of Streams
  • 5.2 Getting Standard Data Structures Into and Out of Streams
  • 5.3 Core Stream Methods: Overview
  • 5.4 forEach – Calling a Lambda on Each Element of a Stream
  • 5.5 map – Transforming a Stream by Passing Each Element through a Function
  • 5.6 filter – Keeping Only the Elements that Pass a Predicate
  • 5.7 findFirst – Returning the First Element of a Stream while Short-Circuiting Earlier Operations
  • 5.8 Lazy Evaluation
  • 5.9 Wrap-Up

Lesson 6: Streams Part 2

  • Learning objectives
  • 6.1 reduce: Combining Stream Elements
  • 6.2 collect: Fancier Stream Output
  • 6.3 Operations that Limit the Stream Size: limit, substream
  • 6.4 Operations that Use Comparisons: sorted, min, max, distinct
  • 6.5 Operations that Check Matches: allMatch, anyMatch, noneMatch, count
  • 6.6 Parallel Streams
  • 6.7 Infinite (Unbounded On-the-Fly) Streams
  • 6.8 Wrap-Up

Summary

  • Summary of Java 8: Lambda Expressions and Streams LiveLessons

 

Email: edwardthienhoang@gmail.com

http://www.edwardthienhoang.wordpress.com

Java

Java 8 Tutorial: Giới thiệu Nashorn Engine

Java 8 Tutorial: Giới thiệu Nashorn Engine

1.Giới thiệu

Sự ra đời của Java 8 trong năm 2014 này có rất nhiều thay đổi mới trong đó chúng ta phải kể đến việc phát triển Nashorn Engine nhằm thay thế cho Rhino Engine cũ và tích hợp chúng vào trong JVM để làm cho lập trình Java và javascript trở nên dễ dàng hơn và có hiệu năng cao hơn. trong bài này tôi giới thiệu với các bạn về Nashorn và cách sử dụng chúng trong Java 8.

2. Nashorn là gì?

Nashorn là một engine thực thi javascript mới, tương tự như các engine V8 của trình duyệt Chrome hay SquirrelFish engine của WebKit. Từ năm 1997, Java đã có thể làm việc (hạn chế) với javascript thông qua engine Rhino; trong Java 7, việc thực thi javascript trên JVM thông qua cơ chế invokeDynamic. Với Java 8, bằng việc tích hợp hoàn toàn Nashorn vào JVM, lập trình viên có thể sử dụng javascript khai thác các thư viện có sẵn của java và ngược lại. Theo thử nghiệm thì Nashorn chạy nhanh gấp 5 lần Rhino và đòi hỏi ít bộ nhớ hơn.

3. Tại sao Nashorn lại được phát triển?

Nó được phát triển để thay thế cho javascript engine đã quá cũ trong jvm từ năm 1997
Tạo ra cầu nối giữa java và javascript. ( cây cầu này được tạo ra trong môi trường JVM)
Giải quyết vấn đề không tương thích giữa java và javascript.
Nâng cao performance của việc thực thi javascript trong java. thay thế cho Rhino engine đã quá lỗi thời.
Bằng việc tích hợp javascript trong java code. bạn có thể chỉnh sửa, mở rộng, sử dụng các ưu điểm của các api có sẵn trong java. (nghĩa là bạn có thể truy cập và sử dụng các thư viện có sẵn trong java để thực thi từ javascript)

4. Script engine & script language là gì?

Scripting engine: là một trình thông dịch của các ngôn ngữ scripting. được viết sẵn trong java JDK nằm trong javax.script package.
Script language: là ngôn ngữ lập trình có hỗ trợ có khả năng viết các script (php,ruby, python , javascript..). đối với các ngôn ngữ cần biên dịch như java, .net thì cần phải có trình biên dịch dịch ra mã bytecodes trước khi chúng được chạy. còn đối với script language thì chúng chỉ được dịch tại thời điểm chạy. bởi một script engine.
Hầu hết các script language đều là có khai báo các kiểu dữ liệu động. (nghĩa là có thể khai báo các kiểu dữ liệu khác nhau cho cùng một biến., và khi bạn tạo một biến cũng không cần phải khai báo kiểu dữ liệu. chỉ khi nào bạn chạy nó thì mới cần khai báo.).
Tài liệu “Java Specification Request (JSR) 223″ có mô tả rõ những vấn đề gặp phải khi tích hợp java và javascript trong java. http://jcp.org/en/jsr/detail?id=223

5. Javascripting API:

Nó là sự cài đặt JSR 223 trong ứng dụng java. Nhằm để nhúng javascript vào trong java.

6. Nashorn engine:

Là một javascript engine viết dựa trên tài liệu mô tả của ECMAScript (javascript) engine được tích hợp trong JDK. nó đã được phát triển đầy đủ bởi oracle và được tích hợp trong jdk8. tương thích hoàn toàn với javascript.

7. Làm thế nào để sử dụng Nashorn?

Cần import thư viện javax.script.*; để sử dụng script engine trong java.
khởi tạo một đối tượng Nashorn Script Engine sử dụng ScriptEngineManager của java.
sử dụng script engine vừa tạo để thực hiện một đoạn mã javascript.

VD :

 import javax.script.*;
 public class EvalScript { 
 public static void main(String[] args) throws Exception { 
 ScriptEngineManager manager = new ScriptEngineManager(); 
 ScriptEngine engine = manager.getEngineByName("nashorn");
    // evaluate JavaScript code
   engine.eval("print('Hello, World')");
 }}

 

8. Các cách sử dụng các thư viện có sẵn của Java bằng script engine

sử dụng các class của Java.

import javax.script.*;
public class EvalFile {
public static void main(String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");

    // evaluate JavaScript code
    engine.eval(new java.io.FileReader("script.js"));
}}

Đưa một object của Java thành một biến global của script engine:

import javax.script.*; 
import java.io.*;
public class ScriptVars { public static void main(String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager(); 
ScriptEngine engine =  manager.getEngineByName("nashorn");

    // create File object
    File f = new File("test.txt");
    // expose File object as a global variable to the engine
    engine.put("file", f);
    // evaluate JavaScript code and access the variable
    engine.eval("print(file.getAbsolutePath())");
}}

Thực thi một Script function từ script engine.

  import javax.script.*;
  public class InvokeScriptFunction { 
  public static void main(String[] args) throws Exception { 
  ScriptEngineManager manager = new ScriptEngineManager();
  ScriptEngine engine = manager.getEngineByName("nashorn");

    // evaluate JavaScript code that defines a function with one parameter
    engine.eval("function hello(name) { print('Hello, ' + name) }");

    // create an Invocable object by casting the script engine object
    Invocable inv = (Invocable) engine;

    // invoke the function named "hello" with "Scripting!" as the argument
    inv.invokeFunction("hello", "Scripting!");
}
}

Thực thi một script method của Object

 import javax.script.*;
 public class InvokeScriptMethod { 
 public static void main(String[] args) throws Exception {
 ScriptEngineManager manager = new ScriptEngineManager();
 ScriptEngine engine = manager.getEngineByName("nashorn");

    // evaluate JavaScript code that defines an object with one method
    engine.eval("var obj = new Object()");
    engine.eval("obj.hello = function(name) { print('Hello, ' + name) }");

    // expose object defined in the script to the Java application
    Object obj = engine.get("obj");

    // create an Invocable object by casting the script engine object
    Invocable inv = (Invocable) engine;

    // invoke the method named "hello" on the object defined in the script
    // with "Script Method!" as the argument
    inv.invokeMethod(obj, "hello", "Script Method!");
   }}

chú ý: không phải tất các các script engine đều được cài đặt Invocable interface. trong ví dụ trên thì chúng ta sử dụng nashorn engine đã được cài đặt invocabkle interface.

Cài đặt một Java interface bằng script functions:

   public class ImplementRunnable {
   public static void main(String[] args) throws Exception {
   ScriptEngineManager manager = new ScriptEngineManager();
   ScriptEngine engine = manager.getEngineByName("nashorn");

    // evaluate JavaScript code that defines a function with one parameter
    engine.eval("function run() { print('run() function called') }");

    // create an Invocable object by casting the script engine object
    Invocable inv = (Invocable) engine;

    // get Runnable interface object
    Runnable r = inv.getInterface(Runnable.class);

    // start a new thread that runs the script
    Thread th = new Thread(r);
    th.start();
    th.join();
} }

Cài đặt một Java interface bằng script object methods.

  import javax.script.*;
  public class ImplementRunnableObject {
  public static void main(String[] args) throws Exception {
  ScriptEngineManager manager = new ScriptEngineManager();
  ScriptEngine engine = manager.getEngineByName("nashorn");

    // evaluate JavaScript code that defines a function with one parameter
    engine.eval("var obj = new Object()")
    engine.eval("obj.run = function() { print('obj.run() method called') }");

    // expose object defined in the script to the Java application
    Object obj = engine.get("obj");

    // create an Invocable object by casting the script engine object
    Invocable inv = (Invocable) engine;

    // get Runnable interface object
    Runnable r = inv.getInterface(obj, Runnable.class);

    // start a new thread that runs the script
    Thread th = new Thread(r);
    th.start();
    th.join();
 } }

Sử dụng biến trong các phạm vi khác nhau.

  public class MultipleScopes { 
  public static void main(String[] args) throws Exception {
  ScriptEngineManager manager = new ScriptEngineManager(); 
  ScriptEngine engine = manager.getEngineByName("nashorn");

    // set global variable
    engine.put("x","hello");

    // evaluate JavaScript code that prints the variable (x = "hello")
    engine.eval("print(x)");

    // define a different script context
    ScriptContext newContext = new SimpleScriptContext();
    newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
    Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);

    // set the variable to a different value in another scope
    engineScope.put("x", "world");

    // evaluate the same code but in a different script context (x = "world")
    engine.eval("print(x)", newContext);
} }

 

9. sử dụng truy cập đến các thư viện có sẵn của Java trong script engine

primitive data type:

   var ArrayList = Java.type("java.util.ArrayList"); 
   var intType = Java.type("int");
   var StringArrayType = Java.type("java.lang.String[]"); 
   var int2DArrayType = Java.type("int[][]");

* Object data type:

      var ArrayList = Java.type("java.util.ArrayList");
      var defaultSizeArrayList = new ArrayList;
      var customSizeArrayList = new ArrayList(16);

Truy cập inner class bằng $ sign:

var Float = Java.type("java.awt.geom.Arc2D$Float");

sử dụng import class or package:

   // Load compatibility script 
   load("nashorn:mozilla_compat.js");
   // Import the java.awt package 
   importPackage(java.awt); 
 // Import the java.awt.Frame class
  importClass(java.awt.Frame); 
  // Create a new Frame object 
  var frame = new java.awt.Frame("hello"); 
  // Call the setVisible() method 
  frame.setVisible(true);
  // Access a JavaBean property 
  print(frame.title);

Nashorn thực sự là một cầu nối giữa Java và javascript. Nó thực sự đã làm cho việc thực thi nhiều ngôn ngữ trong Java trở nên dễ dàng hơn, nâng cao hiệu năng xử lý javascript trong Java

Nguồn:

http://tech.blog.framgia.com/vn/?p=2857

Những điểm mới trong Java 8

Java

Java 8 Tutorial: Arrays.parallelSort

Java 8 Tutorial: Arrays.parallelSort

Trước Java 8, chúng ta thường dùng phương thức Arrays.sort để sắp xếp một array. Trong Java 8 chúng ta có thêm một lựa chọn nữa đó là phương thức Arrays.parallelSort.

Về mặt giải thuật, cả 2 phương thức đều dùng phương pháp sắp xếp trộn (merge sort) để sắp xếp array. Còn về mặt xử lý, cái tên parallel cho thấy sẽ có những xử lý song song trong quá trình sắp xếp bằng cách sử dụng Fork/Join framework được giới thiệu từ Java 7. Nó dựa vào các thread “available” trong thread pool để thực hiện công việc sắp xếp đồng thời.

Demo

Sau đây là đoạn code so sánh thời gian thực hiện việc sắp xếp giữa 2 phương thức Arrays.sort và Arrays.parallelSort

public class ArraysParallelDemo {
  public static void main(String[] args) throws FileNotFoundException {
    List<Double> arraySource = new ArrayList<>();

    Scanner reader = new Scanner(ClassLoader.
        getSystemResourceAsStream("java8demo/large_array_input"));
    while(reader.hasNext()){
      String line = reader.nextLine();
      String[] strNums = line.split(",");
      for ( String strN : strNums){
          arraySource.add(Double.parseDouble(strN));
      }
    }

    System.out.println(arraySource.size());

    Double [] myArray = new Double[1];
    myArray = arraySource.toArray(myArray);
    long startTime = System.currentTimeMillis();
    Arrays.sort(myArray);
    long endTime = System.currentTimeMillis();
    System.out.println("Time take in serial: "+
        (endTime-startTime)/1000.0);

    Double [] myArray2 = new Double[1];
    myArray2 = arraySource.toArray(myArray);
    startTime = System.currentTimeMillis();
    Arrays.parallelSort(myArray2);
    endTime = System.currentTimeMillis();
    System.out.println("Time take in parallel: "+
        (endTime-startTime)/1000.0);

  }
}

Kết quả

Table_ParallelSort2

Graph_ParallelSort2

Không có gì ngạc nhiên khi thấy việc sắp xếp “đa nhân” nhanh hơn sắp xếp trên 1 nhân. Lưu lý là test được thực hiện trên máy tính có CPU 4 nhân.

Kết thúc bài giới thiệu về Arrays.parallelSort 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 8 Tutorial

http://www.edwardthienhoang.wordpress.com

Java

Java 8 Tutorial Series

Gần 2 năm rưỡi sau khi phiên bản Java 7 ra đời, ngày 18/3/2014, Oracle chính thức giới thiệu thế hệ tiếp theo: Java 8. Phiên bản mới này được xem là Java-7-hoàn-thiện-hơn bởi vì nhiều tính năng quan trọng trong Java 8 theo kế hoạch ban đầu thì thuộc về Java 7, nhưng các chậm trễ trong quá trình phát triển đã khiến Oracle quyết định ra đời Java 7 gọn nhẹ hơn, với lời hứa sẽ giới thiệu những tính năng còn thiếu trong phiên bản kế tiếp.

Đây là loạt bài viết về những tính năng mới có mặt trong Java 8.

Series Java 8 Tutorial

 

Java 9 và kế hoạch cho tương lai

Oracle đã bắt đầu quá trình phát triển phiên bản tiếp theo là Java 9 với dự kiến phát hành trong năm 2016. Chưa có danh sách các tính năng sẽ đưa vào Java 9 ngoài những mục tiêu chung chung như hỗ trợ ứng dụng cần heap lớn, tích hợp tốt hơn với CPU theo hướng thực hiện song song nhưng tác vụ xử lý nặng, JVM sẽ tự điều chỉnh để chạy ngày càng tốt hơn,… Java 9 là bước đệm để java chuyển hoàn toàn sang thế hệ 64-bit, từ Java 10 thì JDK sẽ chỉ có phiên bản x64.

Java 8 hay và dở

Đối với nhiều lập trình viên java lâu năm, java 8 là phiên bản đáng mong đợi, với biểu thức lambda và động cơ Nashorn, năng suất của lập trình viên có thể tăng đáng kể.

Đối với người mới học java, những cải tiến này làm java mất tính trong sáng và có thể gây bối rối (đặc biệt là phương thức default cho interface).

Đối với sự phát triển ngôn ngữ, từ một ngôn ngữ tiên phong khi mới ra đời (1995), java đã dần dần mất đi vị trí dẫn đầu và định hướng cho sự phát triển các ngôn ngữ lập trình. Những cải tiến như biểu thức lambda, phương thức mặc định cho interface hay các phương thức sắp xếp song song trên Array,… là sự học tập một cách vụng về các tiếp cận vấn đề của C#.

 

http://www.edwardthienhoang.wordpress.com

Java

Java 8 Tutorial: Optional

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

Java

Java 8 Tutorial: Method Reference

Java 8 Tutorial: Method Reference

Đi cùng với Lambda Expression, Java 8 có thêm một khái niệm mới là Method Reference. Chúng ta thường dùng Lambda Expression để tạo ra các method vô danh (anonymous method), nhưng đôi lúc Lambda Expression cũng có thể tham chiếu đến các phương thức có sẵn để thực thi. Tất nhiên là phương thức đó phải có các tham số đầu vào và kiểu trả về tương ứng với Lambda Expression.

Việc tham chiếu đến các phương thức có sẵn được thực hiện qua toán tử “::“. Hãy xem một ví dụ dưới đây.

Sử dụng Lambda expression để sort 1 arraylist

import java.util.ArrayList;
import java.util.List;

public class MethodReference {
	public static void main(String[] args) {
		// Initialize an array
		List arr = new ArrayList();
		arr.add(3);
		arr.add(4);
		arr.add(5);
		arr.add(1);
		arr.add(2);
		// Sort array using Lambda Expression
		arr.sort((x, y) -> {return (x  y) ? 1 : 0);});
		// Print out
		arr.forEach((x) -> System.out.println(x));
	}
}

Thay vì phải định nghĩa ra Lambda Expression, nếu chúng ta đã có sẵn 1 Comparator thì vẫn có thể dùng lại được.

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class MethodReference {
	public static void main(String[] args) {
		// Initialize an array
		List arr = new ArrayList();
		arr.add(3);
		arr.add(4);
		arr.add(5);
		arr.add(1);
		arr.add(2);
		// Sort array using Lambda Expression
		arr.sort(MethodReference::compare);
		// Print out
		arr.forEach((x) -> System.out.println(x));
	}
	// Existing comparison logic
	// This method has the same signature
	// with method compare in Comparator class which is a Functional Interface
	// and is applied as a parameter in List.sort method
	public static int compare(Integer x, Integer y) {
		return (x  y) ? 1 : 0);
	}
}

Lambda Expression đã tham chiếu đến hàm static compare trong lớp MethodReference để định nghĩa logic sort qua câu lệnh

MethodReference::compare

Hàm compare này có cú pháp giống như hàm compare trong interface Comparator. Comparator là 1 Functional Interface vì nó chỉ có duy nhất 1 hàm abstract là compare. Phương thức List.sort nhận vào 1 đối số là Lambda Expression đại diện cho interface Comparator. Vì vậy bất kỳ phương thức nào có cùng cú pháp giống như hàm compare đều được chấp nhận.

Ở ví dụ trên chúng ta dùng static method reference. Trong Java 8 hỗ trợ 4 kiểu reference là:

  • Reference to a static method
  • Reference to an instance method of a particular object
  • Reference to an instance method of an arbitrary object of a particular type
  • Reference to a constructor

Reference to an instance method of a particular object

Ví dụ đơn giản nhất cho kiểu reference này như sau:

package com.edward.tutorial.java8.test;

import java.util.ArrayList;
import java.util.List;

public class Test {

	/**
	 * @param Main method
	 */
	public static void main(String[] args) {
		// Initialize array
		List arr = new ArrayList();
		arr.add(1);
		arr.add(4);
		arr.add(3);
		arr.add(2);

		// Sort it
		arr.sort((x, y) -> (x > y) ? 1 : (x < y) ? -1 : 0);

		// Check it
		arr.forEach(System.out::println);

	}

}

Ở trên, đoạn in ra các phần tử trong array, chúng ta truyền vào 1 Lambda exrepssion tham chiếu đến method println của object out trong lớp System. Nếu viết theo cú pháp Lambda thông thường sẽ như sau:

arr.forEach((x) -> System.out.println(x));

Nghĩa là Lambda expression nhận vào 1 tham số x, và hàm println cũng nhận vào 1 tham số x, vậy có thể thay biểu thức Lambda bằng hàm println đó.

Reference to an instance method of an arbitrary object of a particular type

Hãy xem ví dụ dưới:

String[] stringArray = { "Barbara", "James", "Mary", "John",
	    "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, (x, y) -> { return x.compareToIgnoreCase(y);});

Biến số x ở đây sẽ gọi hàm compareToIgnoreCase, vì vậy chúng ta có thể giản lược x và thay thế bằng method reference như sau:

Arrays.sort(stringArray, String::compareToIgnoreCase);

Reference to a constructor

Tôi sử dụng lại ví dụ trong bài viết Optional kỳ trước. Các bạn có thể đọc bài viết tại đây

Việc thực hiện hàm Optional.orElseThrow được thực hiện như sau:

// 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();
}

Các bạn chỉ cần đến phần tham số truyền vào trong hàm orElseThrow

orElseThrow(() -> {return new Exception();})
orElseThrow(Exception::new)

Biểu thức Lambda không nhận vào đối số nào và trả về 1 đối tượng Expcetion. Điều đó tương đồng với hàm new để khởi tạo 1 đối tượng Exception. Nên ta có thể viết theo cả 2 cách trên.

Kết thúc bài giới thiệu về Method Reference 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