Java 8 Tutorial

Java 8 is a powerful release of Java Platform, give us a big of change from JVM to language and libraries.

Lambda Expressions

Lambda Expressions is a new feature of Java 8 that makes Java code more clearly and easily for development.

static int doMathOperation(int a, int b, IMathOperation mathOperation) {
	return, b);

public static void main(String[] args) {	 
	IMathOperation addition = (int a, int b) -> a + b;
	IMathOperation subtraction = (int a, int b) -> a - b;
	IMathOperation multiplication = (int a, int b) -> a * b;
	System.out.println(doMathOperation(2, 1, addition));
	System.out.println(doMathOperation(2, 1, subtraction));
	System.out.println(doMathOperation(2, 1, multiplication));


Argument List Arrow Token Body Note
(arg1, arg2…) -> { body }
(int a, int b) -> a + b with type declaration
(a, b) -> a + b no type declaration
(int a, int b) -> {return (a + b)} with return statement
a -> a*a*a no parenthesis
() -> 42 no arguments
(String s) -> {System.out.print(s);} returns nothing

– A lambda expression can have zero, one or more parameters.
– No need to declare type of a parameter.
– No need to write parenthesis around parameter if there is only one parameter (required if more).
– No need to use curly braces in expression body if there is only one statement (required if more).
– No need to use return keyword if there is only one statement. The compiler returns the value automatically.

>>> More details at: Java 8 – Lambda Expressions

Functional Interfaces

Functional Interfaces is an interface with only one abstract method inside.

public interface MyFuncInterface {
	void doWork();

@FunctionalInterface annotation is used to annotate for Functional Interface. So compiler will throw errors when the interface is not a valid Functional Interface.

public interface MyFuncInterface {
	void doWork();
	void doAnotherWork();

Invalid '@FunctionalInterface' annotation; MyFuncInterface is not a functional interface

Apply Functional Interfaces:

public interface MyFuncInterface {
	void doWork();

public class MainApp {
	public static void executeFunction(MyFuncInterface func) {

	public static void main(String[] args) {
		executeFunction(new MyFuncInterface() {
			public void doWork() {
				System.out.println("invoke Function using Anonymous Inner Class");
		// with Lambda Expression
		executeFunction(() -> System.out.println("invoke Function using Lambda Expression"));

For Functional Interface with only one method, we can make code lean and beautiful with Lambda Expression, it seem like that we pass a method as argument to a function.

>>> More details at: Java 8 – Functional Interfaces

Method References

Method reference points to the method by its name by replacing a single-method lambda expression.
The syntax of a Method reference is: Object/Class/Type :: methodName

For example, the lambda expression:

s -> System.out.print(s)

can be replaced with the method reference:


There are four kinds of method references:
– Reference to a static method: ContainingClass::staticMethodName
– Reference to an instance method of a particular object: containingObject::instanceMethodName
– Reference to an instance method of an arbitrary object of a particular type: ContainingType::instanceMethodName
– Reference to a constructor: ClassName::new

>>> More details at: Java 8 – Method References


A stream is an abstract concept that represents a sequence of objects created by a source, it’s neither a data structure nor a collection object where we can store items. So we can’t point to any location in the stream, we just interact with items by specifying the functions.

List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
// get List from Stream Operation
List result =
		.filter(i -> (i % 2) == 0)
		.map(i -> "[" + i + "]")


Run the code above, the console shows:

[[2], [4], [6], [8]]

Now, we have concept of using a Stream is to enable functional-style operations on streams of elements. Those operations are composed into a stream pipeline which consists of:
Source > Intermediate Operations > Terminal Operation
– a source (in the example, it is a collection – List, but it is also an array, a generator function, an I/O channel…)
intermediate operations (which transform current stream into another stream at the current chain, in the example, filter is the first operation and map is the second one)
– a terminal operation (which produces a result or side-effect, in the example, it is collect)

>>> More details at: Java 8 – Streams

Optional Class

Null reference causes many problems because it often denotes the absence of a value. Java 8 Optional is a new class that can help us handle these cases instead of checking null.

Instead of Null checking before doing something:

String text = ...;
if (text != null) {

We can use Optionnal ifPresent() method alternatively:

String text = ...;
Optional opText= Optional.ofNullable(text);
opText.ifPresent(s -> System.out.println(s));

>>> More details at: Java 8 – Optional

New Date/Time API

Java 8 provides lots of new Date Time APIs:
– Local Date – Time
– Plus and Minus Date – Time
– TemporalAdjusters
– Period & Duration
– TimeZone
– Formatting and Parsing

>>> More details at: Java 8 – Date Time


Java 8 Base64 provides a standard way to do Base64 encoding and decoding.
There are three types of Base64 encoding:
Basic: Encoder produces a set of characters within A-Za-z0-9+/. Decoder rejects any character NOT mapped to A-Za-z0-9+/.
URL: Encoder produces a URL or safe filename which is set of characters within A-Za-z0-9+_.
MIME: Output is mapped to MIME friendly format.

>>> More details at: Java 8 – Base64

Multithreading – CompletableFutures

Java 8 multithreading programming has an important feature named CompletableFuture. Java has the concept of a Future object, which can help program make something done while waiting for other things. However, although program can inspect Future objects to see if they’re done, what if program want to execute some code whenever its ready? It still has to wait until the result is available. CompletableFuture meets the requirement, and more than that.

Using one of those factory methods to create a CompletableFuture object:

static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier);
static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor);
static CompletableFuture<Void> runAsync(Runnable runnable);
static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor);

If we don’t provide any Executor object as input parameter, the method will use ForkJoinPool.commonPool()

private static final boolean useCommonPool = (ForkJoinPool.getCommonPoolParallelism() > 1);
     * Default executor -- ForkJoinPool.commonPool() unless it cannot
     * support parallelism.
    private static final Executor asyncPool = useCommonPool ?
        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();

In this example, we use that global, general purpose pool ForkJoinPool.commonPool():

CompletableFuture.supplyAsync(new Supplier() {
	public String get() {
		try {
			System.out.println("inside future: waiting for detecting...");
			// process data
			System.out.println("inside future: done...");

			return numbers.get(index);
		} catch (Throwable e) {
			return "not detected";

>>> More details at:
Java 8 CompletableFutures
Java 8 Multiple CompletableFutures
Java 8 CompletableFuture Handle Exception

How to – Practice

How to use Stream Filter in Java 8 with List & Array Examples
How to use Java 8 Stream Map Examples with a List or Array
How to use Java 8 Stream FlatMap Examples with List, Array
How to use Java 8 Stream Reduce Examples with List and Array
Java 8 Stream.collect() – Stream.Collectors APIs Examples
How to use Java 8 Stream Collectors.groupingBy() Examples

Java 8 – Misc

Java Read Text File by BufferedReader, Java 7,Java 8
How to use Java 8 Encode (Decode) an Image to Base64
Java 8 – How to convert List to Map & Map to List
How to use String Joiner with Java 8
Ways to convert an InputStream to String
How to compare Dates in Java

All articles: Java 8