Saturday, November 10, 2018

Java Concurrency - Intrinsic Lock & Reentrancy

Greetings!

Any Java object can implicitly act as a lock for purposes of synchronization. These built-in locks are intrinsic locks.

Java provides synchronized block as a built-in locking mechanism to enforce atomicity.

Java built in object lock is called Intrinsic Lock.


synchronized (lock) {
    // shared data
}


  • When use in method level, invoking object is the lock.
  • Act as a mutex (only one thread at a time)
  • Lock is acquired by the executing thread before entering a synchronized block.

Reentrancy

Thread owning a lock can again acquire the lock is called reentrant lock. Can claim the lock multiple time without blocking itself.
  • Without reentrant lock, there will be a dead lock.
  • Intrinsic locks are re-entrant.
  • Locks are acquired on a per-thread basis rather than per-invocation basis.

Every shared, mutable state should be guarded by the same lock.



Java Concurrency - join()

Greeting!

Let's see the output of below program first.

public class ThreadJoin {

    public static void main(String[] args) {
        System.out.println("start");

        Thread t1 = new Thread(() -> System.out.println("in t1"));
        Thread t2 = new Thread(() -> System.out.println("in t2"));

        t1.start();
        t2.start();

        System.out.println("end");
    }

}


start
end
in t1
in t2


Notice that start and end print before it prints the messages from the threads. This is because thread are running separately hence main thread executes immediately.
What if we want to print end after executing t1 and t2? We can ask main thread to wait for finishing t1 and t2.
It is like a relay race. Second runner is waiting for the first runner to come and hand over the flag to him.
join - execution thread put on wait until this thread is finished.

public class ThreadJoin {

    public static void main(String[] args) {
        System.out.println("start");

        Thread t1 = new Thread(() -> System.out.println("in t1"));
        Thread t2 = new Thread(() -> System.out.println("in t2"));

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("end");
    }

}


start
in t1
in t2
end


"main" thread waited for t1 and t2 to finish there tasks before printing "end".

In a case where the thread is dead locking or taking a long time to finish, join also accepts waiting time in milliseconds.



Java Concurrency - Race Conditions - Read-Modify-Write

Greetings!

When two or more threads access shared data at the same time race condition occurred. These operation should be atomic to thread-safe and we call them "compound actions".

  • read-modify-write - read a value, modify it, write back (ex: increment a value).
  • check-then-act - check a condition and act accordingly; common situation is lazy initialization (ex: singleton pattern).

In this blog post we are going to examine read-modify-write race condition.

Let's say we need a counter and we designed below class.


public class Counter {

    private int count = 0;

    public int getAndIncrement() {
        return count++;
    }

    public int get() {
        return count;
    }

}


Can you spot a possible bug here? Well, for a single threaded application this is working fine. But for a multi-threaded application this will give unexpected results.

Problem here is count++ is not an atomic operation.

Let's create few threads and see the results.


import java.util.stream.IntStream;

public class CounterApp {

    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();

        Thread thread1 = new Thread(() -> IntStream.range(0, 100)
                                                    .forEach(i -> counter.getAndIncrement()));
        Thread thread2 = new Thread(() -> IntStream.range(0, 100)
                                                    .forEach(i -> counter.getAndIncrement()));

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println("Count: " + counter.get());
    }

}


Each thread increment 100 times, so I expected 200 as result. Surprise!!! This gave me results like 155, 200, 140, 196, etc. In each run it gives different results.
(If you are always getting 200, try increasing to a higher value)

what is happening here is both threads read and update (write) the counter at the same time but the changes are not visible.

We can fix this using synchronized.


public class Counter {

    private int count = 0;

    public synchronized int getAndIncrement() {
        return count++;
    }

    public synchronized int get() {
        return count;
    }

}



Java Concurrency - How To Create A Thread

Greetings!

It is easy to create a thread in Java using 2 well known methods.
  • extends Thread class.
  • implement Runnable interface.
Then we create a Thread object and start it! It is as simple as that.


public class ExtendThread extends Thread {
    
    @Override
    public void run() {
        System.out.println("hello from extended thread");
    }
    
}


Thread thread = new ExtendThread();
thread.start();



public class ImplmentedRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println("hello from runnable implementation");
    }
    
}



Thread thread = new Thread(new ImplmentedRunnable());
thread.start();


In Java 8;

Thread thread = new Thread(() -> System.out.println("hello from java 8"));
thread.start();



  • It is not a good practice to extend the Thread class.


Thread states.

A thread exist in several states.
New - when we create an instance of Thread class it is in New state.
Running - when we call start()
Suspended -
Blocked -
Terminated -



Java Concurrency - Thread Safety

Greetings!

What is thread safety?

When we have multiple threads accessing piece of code simultaneously without unwanted side effects we can say our code is thread safe. Correctness!!!

Synchronization

Synchronization allows to control the program flow and access to shared data for concurrently executing threads.

It is tempting to think synchronized is the only way to do this in Java but it is the primary mechanism which provides exclusive locking. volatile variable, explicit locks and atomic variables are other types.

We can synchronize using;
  • mutex lock - allow only one thread at a time to execute a specific section of code (critical section !!)
  • read/write lock - permit concurrent reads and exclusive writes to a protected shared resource.
  • condition variable - block threads until a particular condition is true.
  • semaphore - simply a variable which is a count (counting semaphore) or 0/1 switch (binary semaphore).

How to share mutable state between threads?

  • Don't share at all.
  • Make it immutable.
  • Use proper synchronization mechanism.

Tip :- Always try to use good programming techniques - Object oriented practices, encapsulation, immutability.
Stateless objects are always thread-safe!!!
Atomicity - Set of actions is atomic when all execute as a single operation.
Mutex (Mutual Exclusion) - At a given time only one thread can enter its critical section is called mutual exclusion.
Avoid holding the lock for lengthy computations or operations.

Java Concurrency - Introduction

Greetings!

We can sing while having a bath. We can listen to song while jogging. We are multitasking!. Can a computer to do that? How can a computer do that? As a developer how do we do that? 


Process vs Thread

Let's take word processor as an example. In a word processor there are spell checker, auto correct, etc. Which means within Word application there are sub tasks are running behind the scene. And those tasks share the same address space as the process.
We name those sub tasks as Threads and main task as a Process.

Back in old days, a computer had only one CPU. On the other hand computer could handle only one task at a time. It switch between tasks very quickly so that we can't see the difference. (Time Slice)

Modern computers come with multiple processors allowing multiple tasks to run at the same time.

When dealing with multiple threads we have to think;

  • Two threads update a variable simultaneously.
  • One threads depends on another thread.
  • Two threads are waiting for each other.
  • Thread order (who has the highest priority).
  • Will all the threads get chance to execute?.
  • and more...


Benefits of multi-threading

  • Better resource utilization.
  • Fairness
  • Better performance.
  • More responsive

Costs of multi-threading

  • Complex design.
  • CPU overhead to switch between threads.

Issues with multi-threading

In a multi-threaded application will mainly face two kind of problems.
  • Visibility issue - One thread change the data while the other thread reading it unaware of the change.
  • Access issue - Change same shared data.
Eventually these will lead to;
  • liveness failure - stop reacting (deadlock)
  • safety failure - incorrect data produces (race conditions)
  • performance - due to switch between threads

Java Collections - Lists

Greetings!

It is probably Lists are the most used Collections.
  • Can have duplicates.
  • Maintain the element order.
  • Can iterate in added order.

Lists maintain the added order. Hence it can be accessed by given position. List interface have additional methods to fulfill this requirement.


// add, remove in given position
void add(int index, E e)
E get(int index)
E remove(int index)
E set(int index, E e)

// search position by object
int indexOf(Object o)
int lastIndexOf(Object o)

// get a sub list by given positions (toIndex exclusive)
List<E> subList(int fromIndex, int toIndex)

// get listiterator
ListIterator<E> listIterator()

  • subList doesn't return a new list. It returns a view of the existing list by given positions. Because of this changing the original list changes the sub list. But changing the sub list doesn't affect the original list.
  • ConcurrentModificationException can be occurred if the original list is changed and try access the sub list.
  • ListIterator has methods to traverse backward using hasPrevious(), previous()

Additionally, Lists implement RandonAccess interface.

ArrayList

  • Implemented as a re-sizable array.
  • add, remove in middle is slow (to shift index).
  • Can get from any position.

LinkedList

  • Implemented as a double linked list.
  • add, remove is fast. (since only the link is affected)
  • accessing an element is slower. (have to traverse through links)

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.IntStream;

public class ListsApp {

    public static void main(String[] args) {
        // add operation
        long start = System.nanoTime();
        List<String> arrayList = new ArrayList<>();
        IntStream.range(0, 10000).forEach(i -> arrayList.add("Hello"));
        long arrayListAdd = System.nanoTime() - start;

        start = System.nanoTime();
        List<String> linkedList = new LinkedList<>();
        IntStream.range(0, 10000).forEach(i -> linkedList.add("Hello"));
        long linkedListAdd = System.nanoTime() - start;
        
        System.out.println(arrayListAdd - linkedListAdd);
        
        // get operation
        start = System.nanoTime();
        IntStream.range(0, 10000).forEach(i -> arrayList.get(i));
        long arrayListGet = System.nanoTime() - start;
        
        start = System.nanoTime();
        IntStream.range(0, 10000).forEach(i -> linkedList.get(i));
        long linkedListGet = System.nanoTime() - start;
        
        System.out.println(arrayListGet - linkedListGet);
    }

}




Java Collections - Interfaces

Greetings!

There are number of data structures. To handle varies kind of collections, Collection framework has different interfaces.

  • Collection - fundamental interface for most of the collections
  • Set  - no duplicates. no order.
  • List - ordered collection. contain duplicates. can access using position.
  • Queue - typically has first-in-first-out structure.
  • Deque - double-ended queue. can behave both as first-in-first-out and last-in-last-out. can insert and remove from both ends.
  • SortedSet - maintain sort order
  • Map - contains key-value pairs. no duplicates allowed.
  • SortedMap - maintain sorted key order

Collection Interface


Map Interface


Iterator


Other than that, there is RandomAccess interface.


Java Collections - Collection Interface

Greetings!

Collection interface is the base interface for most of the classes in Collection Framework. It mainly contains methods for add, remove and iteration.


public interface Collection<E> {

    boolean add(E element);

    Iterator<E> iterator();

    boolean remove(Object o);

    // ....
}


Other than that this contains a lot of common utility methods.


int size()
boolean isEmpty()
boolean contains(Object obj)
boolean containsAll(Collection<?> c)
boolean equals(Object other)
boolean addAll(Collection<? extends E> from)
boolean remove(Object obj)
boolean removeAll(Collection<?> c)
void clear()
boolean retainAll(Collection<?> c)
Object[] toArray()
<T> T[] toArray(T[] arrayToFill)


Java 8 has introduced new default methods to convert the Collection into a stream.


default Stream<E> stream()
default Stream<E> parallelStream()
default boolean removeIf(Predicate<? super E> filter)


  • There is no concrete implementation of Collection interface. Instead it has several sub interfaces to handle different kind of Collections.
  • Because most of the utility methods are common, there is partially implemented AbstractCollection that other implementation can extend. (this can be removed with Java 8 default methods)



Java Collections - ConcurrentModificationException

Greetings!

When you use a collection and suddenly encounter ConcurrentModificationException it is very confusing. Why are we getting this when we are not using multi-threading?

Actually this doesn't mean you are using multi-threading. This means that the collection in used is modified (add/remove).

For an example let's say we want remove multiples of 3 from an array list.


List<Integer> numbers = IntStream.range(1, 20).boxed().collect(toList());

for (Integer number : numbers) {
    if (number % 3 == 0) {
        numbers.remove(number - 1);
    }
}


This little program will throw java.util.ConcurrentModificationException because we are modifying the collection directly while iterating.

Underline iterator is implemented so that it checks for any modification. If it found any modification it throws new ConcurrentModificationException.

Instead of removing items from the collection, we need to remove it from the iterator.


List<Integer> numbers = IntStream.range(1, 20).boxed().collect(toList());

Iterator<Integer> iterator = numbers.iterator();

while (iterator.hasNext()) {
    if (iterator.next() % 3 == 0) {
        iterator.remove();
    }
}


In Java 8, above while loop has been added to Collection interface as a default method;


List<Integer> numbers = IntStream.range(1, 20).boxed().collect(toList());

numbers.removeIf(number -> number % 3 == 0);




Java Collections - Iterable and Iterator

Greetings!

It is easily misunderstand that Collection interface is the super interface in JCF. Actually, Collection interface extends Iterable interface.


public interface Iterable<T> {

    Iterator<T> iterator();

}



Idea of this is to give a common way traverse the underline collection using the Iterator.


public interface Iterator<E> {

    boolean hasNext();

    E next();

    void remove()

}



Prior to Java 5, for loop was used as below,


for (Iterator iterator = collection.iterator(); iterator.hasNext(); ) {
   iterator.next();
}



With Java 5 foreach loop, iterators are used internally by the compiler and it is simplified.


for (SomeObject object : collection) {

   // ....

}



With Java 8 lambda expressions both Iterable and Iterator interfaces are updated to simplify this even more.


iterator.forEachRemaining(element -> {

   // do something

});


collection.foreach(element -> {

   // do something

});



next() and remove()

When we call next(), iterator jumps to the next element and return it. It is like it cosumes the current element.
remove() method remove an element which is returned by the next(). That mean if we want to remove an item we first need to receive it.

Let's say we need to remove the first number from an given numbers collection;


Iterator<Integer> iterator = numbers.iterator();
iterator.remove();


This throws IllegalStateException. Correct way to do this is first load it.


Iterator<Integer> iterator = numbers.iterator();
iterator.next();
iterator.remove();


To remove an element, you must call next() to jump over to it.

Java Collections - Introduction

Greetings!

We have to use different kind of data structures and algorithms in our code. Luckily for us, Java provide Java Collection Framework (JCF) for that purpose.

Prior to Java 1.2 Java had only few data structures like Vector, Stack, Hashtable, Enumeration.

Java 2 introduced proper collection API to address all data structures issues.
  • Easy to use collections.
  • High performance.
  • Easy to extend.
There is no "one for all" implementation.

Common Interfaces

  • Iterable - provide iteration through a collection. (this is outside of the api)
  • Collection - main interface for the most of the collections. contains most of the core functionalities.
  • Set - can not have duplicate. contains unique elements. doesn't maintain the insertion order.
  • List - maintain the order. can have duplicates.
  • Queue - define first in first out data structure.
  • Map - key, value pairs.

In Collection API, interfaces provide the necessary contract but it doesn't give us an idea about real algorithm used. Multiple implementations have multiple purposes, hence we need to check the implemented class also to get the real idea.

How do they implemented?

  • Array - arrays maintain adjacent positions and implemented directly in hardware. Because it maintains the position removal and insertion at given position is slow. Read at a given point, iteration is fast. (ArrayList, CopyOnWriteArrayList, EnumSet, EnumMap)
  • Linked list - maintain a link to next item (and to previous item). Reading in middle is slow due to this. But insertion and removal is fast. (LinkedList)
  • Hashtable - index by content. no support to access by position. (Set, Map)
  • Trees - organize by content but can store and retrieve in sorted order. (TreeSet, TreeMap)

Friday, November 9, 2018

Java 8 - Streams - How to Create a Stream?

Greetings!

It is easy to guess that we can create a Stream using a collection. Actually it is one of the ways to create a Stream.

Stream from collections


Stream<Employee> stream = employees.stream();


Stream from values

Using static Stream.of() we can create a stream using given values.

Stream<String> countryStream = Stream.of("Sri Lanka", "India", "Pakistan");
Stream<Integer> integerStream = Stream.of(1, 2, 3);
Stream<Employee> employeeStream = Stream.of(new Employee());


Stream from arrays

Arrays class has Arrays.stream() static method to convert given array into a stream.

int[] intArray = { 1, 2, 3, 4, 5 };
IntStream intStream = Arrays.stream(intArray);
String[] stringArray = { "Hello", "World" };
Stream<String> stringStream = Arrays.stream(stringArray);


Stream from files

Files class has static methods to open a file as a stream.

// from a file
try (Stream<String> linesStream = Files.lines(Paths.get("pom.xml"))) {
   linesStream.forEach(System.out::println);
} catch (IOException e) {
    e.printStackTrace();
}

// print files in current working directory
try (Stream<Path> paths = Files.list(Paths.get(""))) {
    paths.forEach(System.out::println);
} catch (IOException e) {
    e.printStackTrace();
}


Stream from numeric ranges


// Inclusive. Up to 100
IntStream.rangeClosed(1, 100).forEach(System.out::println);

// Exclusive. Up to 99
IntStream.range(1, 100).forEach(System.out::println);

// With Steps
IntStream.iterate(0, i -> i + 2).limit(50).forEach(System.out::println);



Java 8 - Streams - Replace Traditional for Loops

Greetings!

It is very common to have numeric iterations like below;


for (int i = 1; i <= 100; i++) {
    // do something
}


Java 8 has static methods for this common task in IntStream and LongStream.

IntStream intStream = IntStream.rangeClosed(1, 100);

// Inclusive. Up to 100: 1, 2, ..., 99, 100
IntStream.rangeClosed(1, 100).forEach(System.out::println);

// Exclusive. Up to 99: 1, 2, ..., 98, 99
IntStream.range(1, 100).forEach(System.out::println);

// With Steps: 1, 2, ..., 98, 100
IntStream.iterate(0, i -> i + 2).limit(50).forEach(System.out::println);

Note that iterate produces an infinite stream.

Java 8 - Streams - Numeric Streams

Greetings!

It is common to have numeric operations min, max, sum in our code. Stream interface have min and max methods but doesn't have sum method because it make no sense to have it.
Even though we can have sum operation using reduce() it has unboxing cost. This is same for min, max operations.
Considering those factors, Stream API provides separate interfaces for primitives. IntStream, LongStream and DoubleStream.

Convert to numeric stream

stream.mapToInt() - return IntStream
stream.mapToLong() - return LongStream
stream.mapToDoulbe() - return DoubleStream


IntStream intStream = stream.mapToInt()


Convert back to stream of objects

numericStream.boxed()


String<Integer> = intStream.boxed()


Optional values

For primitive operations Optional also have corresponding primitive optionals.
OptionalInt, OptionalLong, OptionalDouble

There are corresponding functional interfaces like IntPredicate, IntConsumer, IntUnaryOperator for numeric operations.

Example:-

import java.util.Arrays;
import java.util.List;
import java.util.OptionalDouble;
import java.util.OptionalInt;

public class NumericApp {

    public static void main(String[] args) {
        List<Subject> subjects = Arrays.asList(
                Subject.newInstance("Maths", 95), Subject.newInstance("Enlighs", 98),
                Subject.newInstance("Music", 70), Subject.newInstance("Science", 84),
                Subject.newInstance("History", 92));
        
        int total = subjects.stream().mapToInt(Subject::getMarks).sum();
        OptionalInt min = subjects.stream().mapToInt(Subject::getMarks).min();
        OptionalInt max = subjects.stream().mapToInt(Subject::getMarks).max();
        OptionalDouble average = subjects.stream().mapToInt(Subject::getMarks).average();
        
        System.out.println("total: " + total);
        System.out.println("min: " + min);
        System.out.println("max: " + max);
        System.out.println("average: " + average);
    }

}


public class Subject {

    private String name;
    private Integer marks;

    private Subject(String name, Integer marks) {
        this.name = name;
        this.marks = marks;
    }
    
    public static Subject newInstance(String name, Integer marks) {
        return new Subject(name, marks);
    }

    public String getName() {
        return name;
    }

    public Integer getMarks() {
        return marks;
    }

}



Java 8 - Streams - sum()

Greetings!

Let's say we want to calculate total marks for a student for all subjects.


public class Subject {
    private String name;
    private Integer marks;
}


int totalMarks = subjects.stream().map(Subject::getMarks).sum();


This is not working because stream doesn't have sum() operation. That make sense because stream is generic and it doesn't have any meaning for total (sum) operation for an object.
And also if we use Integer, behind the scene it will covert to int (unboxing). For a large data set this will be a costly operation.
So, to get our desired result we to need to convert our stream into IntStream which offers the sum operation.


int totalMarks = subjects.stream().mapToInt(Subject::getMarks).sum();



  • mapToInt - this intermediate operation returns IntStream



Java 8 - Streams - Terminal Operations

Greetings!

Terminal operations are used to close the stream and generate a result. This is the last operation in a stream pipeline hence eagerly executed. Can return concrete value types like (Integer, String, List, Optional), primitive value (int, long) or void.

Ex:-
forEach, collect, count, anyMatch, nonMatch, allMatch, findAny, findFirst, reduce, min, max, sum are terminal operations.

Let's use employee data set for all operations.
(Complete code is here)


public class Employee {
    
    enum Gender { MALE, FEMALE };
    
    private String name;
    private int age;
    private Gender gender;
    
    private Employee(String name, int age, Gender gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    
    public static Employee newInstance(String name, int age, Gender gender) {
        return new Employee(name, age, gender);
    }

    // getters

}



    private static List<Employee> employees = Arrays.asList(
            Employee.newInstance("Jon", 22, Gender.MALE),
            Employee.newInstance("Arya", 16, Gender.FEMALE),
            Employee.newInstance("Tyrion", 30, Gender.MALE),
            Employee.newInstance("Ghost", 5, Gender.MALE),
            Employee.newInstance("Joffery", 20, Gender.MALE),
            Employee.newInstance("Hound", 35, Gender.MALE),
            Employee.newInstance("Danny", 23, Gender.FEMALE)
    );


forEach()

Perform an action for each element in stream. Return type is void.


employees.stream()
            .filter(employee -> employee.getAge() > 20)
            .forEach(System.out::println);


collect()

Reduce the stream into another container such as collection.


employees.stream()
            .filter(employee -> employee.getAge() > 20)
            .collect(Collectors.toList());


count()

Return the total number of elements in the stream.


long count = employees.stream().count();

System.out.println(count);

long femaleCount = employees.stream()
                             .filter(employee -> Gender.FEMALE.equals(employee.getGender()))
                             .count();

System.out.println(femaleCount);


min()

This is a special reduction operation. This returns the minimum value of the stream by given comparator. This return an Optional value.


Optional<Employee> min = employees.stream()
          .min((e1, e2) -> e1.getAge() - e2.getAge());

System.out.println(min);


max()

Same as min operation, this return maximum value.


Optional<Employee> max = employees.stream()
          .max((e1, e2) -> e1.getAge() - e2.getAge());

System.out.println(max);


allMatch()

Check whether all elements in the stream match the given condition.


boolean allMatch = employees.stream()
                            .allMatch(employee -> Gender.MALE.equals(employee.getGender()));
System.out.println("Are all employees male ? " + allMatch);


anyMatch()

Check whether any of the elements in stream matches the given condition.


boolean anyMatch = employees.stream()
                            .anyMatch(employee -> Gender.FEMALE.equals(employee.getGender()));
System.out.println("Is there any female ? " + anyMatch);


nonMatch()

Return true if no element in stream matches the given condition.


boolean noneMatch = employees.stream()
                            .noneMatch(employee -> employee.getAge() > 50);
System.out.println("Is there no one above 50 ? " + noneMatch);


findAny()

As the name suggest this returns any element from the stream.


Optional<Employee> any = employees.stream().findAny();
System.out.println(any);

Optional<Employee> anyFemale = employees.stream()
        .filter(employee -> Gender.FEMALE.equals(employee.getGender()))
        .findAny();
System.out.println(anyFemale);


findFirst()

This returns the first element in the stream.


Optional<Employee> first = employees.stream().findFirst();
System.out.println(first);

Optional<Employee> firstFemale = employees.stream()
                                            .filter(employee -> Gender.FEMALE.equals(employee.getGender()))
                                            .findFirst();
System.out.println(firstFemale); 



Java 8 - Streams - Intermediate Operations

Greetings!

Intermediate operations are used to transform the stream into another. These operations can be chained and merge internally as necessary. Lazily process and process only when a terminal operations is called.

Ex:-
map, flatMap, filter, distinct, limit, skip, sorted are intermediate operations

  • Note that forEach is a terminal operation which close the stream.

map()

Convert the iteration element into another.


public static void main(String[] args) {
    List<String> countries = Arrays.asList("Sri Lanka", "India", "Pakistan", "England", "Australia");
    countries.stream().map(String::toUpperCase).forEach(System.out::println);
    countries.stream().map(country -> {
        // create any object and return
        int length = country.length();
        return "Length of ".concat(country).concat(" string is ").concat(String.valueOf(length));
    }).forEach(System.out::println);
}



filter()

Filter the stream elements by given condition.


public static void main(String[] args) {
    List<String> countries = Arrays.asList(
            "Sri Lanka", "India", 
            "Pakistan", "England", 
            "Australia", "South Africa");
    // filter country names started with S
    countries.stream().filter(country -> country.startsWith("S")).forEach(System.out::println);
    
    // filter country names length greater than 5
    countries.stream().filter(country -> country.length() > 5).forEach(System.out::println);
}



distinct()

Select distinct values from the stream.


public static void main(String[] args) {
    List<String> countries = Arrays.asList(
            "Sri Lanka", "India", 
            "Pakistan", "England", "Sri Lanka",
            "Australia", "South Africa", "Pakistan");

    countries.stream().distinct().forEach(System.out::println);
}



limit()

Limit the stream by given value.


public static void main(String[] args) {
    List<String> countries = Arrays.asList(
            "Sri Lanka", "India", 
            "Pakistan", "England",
            "Australia", "South Africa");

    // select only first 3 countries
    countries.stream().limit(3).forEach(System.out::println);
}


skip()

Skip n number of values from the stream.


public static void main(String[] args) {
    List<String> countries = Arrays.asList(
            "Sri Lanka", "India", 
            "Pakistan", "England",
            "Australia", "South Africa");

    // skip first 3 countries
    countries.stream().skip(3).forEach(System.out::println);
}


sorted()

Sort the elements in the stream by given condition.


public static void main(String[] args) {
    List<String> countries = Arrays.asList(
            "Sri Lanka", "India", 
            "Pakistan", "England",
            "Australia", "South Africa");

    // sort by natural order
    countries.stream().sorted().forEach(System.out::println);
    
    // sort by string length
    countries.stream().sorted((first, second) -> Integer.compare(first.length(), second.length()))
                        .forEach(System.out::println);
}




Java 8 - Streams - Introduction

Greetings!

Let's have a look at below code.


List<String> countries = Arrays.asList("Sri Lanka", "India", "Pakistan", "England", "Australia");

for (String country : countries) {
    if (country.length() > 7) {
        String upperCase = country.toUpperCase();
        System.out.println(upperCase);   
    }
}


This code has several problems.
  • Process sequentially. Difficult to process parallel.
  • Complex codes.
  • Instruct how to do it, not what to do.
  • External loop. (developer has to create the loop).

To overcome these kind of problems and get the maximum from multi-core processors Java 8 introduces Stream API.

The same code can be re-written using stream as below.


countries.stream()
        .filter(country -> country.length() > 7)
        .map(country -> country.toUpperCase())
        .forEach(System.out::println);


As you can see it works like builder pattern. We chain several operations using a dot.
We can think of this as a sql query. Instead of how to it, we are instructing what to do.
We didn't provide a loop here, instead it uses internal iteration.

Stream operations have 3 stages.
  • Create stream using an array, collection.
  • Transform stream using intermediate operations.
  • Reduce the result using terminal operations.

Intermediate Operations

Intermediate operations return another stream which helps to connect multiple operations.. These operations doesn't process as in the order we provide. Instead it merge possible operations into a single operation. Another important point is these operations process lazily. Operation doesn't invoke until a terminal operation is called.
Ex:- map, flatMap, filter, distinct, limit

Terminal Operations

These operations end the stream and produce a result. Result is not a stream. It can be void, a List, Integer, etc.
Ex: forEach, collect, reduce, count, max, min

Java 8 - Constructor References

Greetings!

This is same as the method references, except the method name is new.

Class::new


When we have multiple constructors which constructor will be selected? It depends on the context.


(firstName) -> new User(firstName) => User::new
(firstName, lastName) -> new User(firstName, lastName) => User::new


This can also be used with arrays with exact one parameter.

n -> new int[n]
int[]::new


This helps to create arrays with generic types.

Object[] array = stream.toArray();
User[] users = stream.toArray(User[]::new);


Java 8 - Method References

Greetings!

In Java we have object references. We pass objects around. What if we can pass reference to a method?
In Java 8 if we are executing only one method we can do this using lambda expressions.

For an example these are equal.   
     

(x) -> System.out.print(x)
System.out::print


As you can see, :: separates the name of the method from the class/ object. There are 3 ways we can use method references.
  1. object::method - object.method(parameters)
  2. Class::staticMethod - Class.staticMethod(parameters)
  3. Class::instanceMethod - firstParameter.method(parameters)
In first 2 cases, parameters become the methods parameters. As you can see in System.out::print. If we have more than 1 parameters it is still same,

(x, y) -> Math.pow(x, y)
Math::pow


Third case is different. First parameter becomes the target object of the method and rest become the parameters. For example,

// (object, arguments) -> object.method(arguments)
name -> name.toUpperCase()
String::toUpperCase


We can use this and super also the same way;

this::instanceMethod
super::instanceMethod


inner class => lambda expression => method reference

Java 8 - Functional Interfaces

Greetings!

Functional interface is an interface which has only one abstract method. Runnable, Comparable, ActionListener are few existing examples.
interface with only one abstract method.
You can have many methods in the interface but should have only one abstract method.

To ensure that an interface has only one abstract method, Java8 comes with @FunctionalInterface annotation. It is not mandatory to have this, but with this compiler warns you when you break the contract.

We can avoid inner classes' and use lambda expression in place of these interfaces.

For an example we can create a thread like this;


Thread thread = new Thread(() -> System.out.println("Hello functional interface"));
thread.start();


Let's say we have fruits names and we need to print them according to given condition.
With prior to Java 8, we can do it like this;


public interface Testable {
    boolean test(String name);
}


import java.util.Arrays;
import java.util.List;

public class WorkerApp {

    public static void main(String[] args) {
        List fruits = Arrays.asList("Apple", "Java Plums", "Mango", "Banana");
        
        test(fruits, new Testable() {
            @Override
            public boolean test(String name) {
                return name.length() == 5;
            }
        });

        test(fruits, new Testable() {
            @Override
            public boolean test(String name) {
                return name.length() > 5;
            }
        });
    }
    
    private static void test(List fruits, Testable testable) {
        for (String name : fruits) {
            if (testable.test(name)) {
                System.out.printf("%s - test passed %n", name);
            }
        }
    }
}


Using lambda expressions we can simply this as;


    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("Apple", "Java Plums", "Mango", "Banana");

        test(fruits, (name) -> name.length() == 5);
        test(fruits, (name) -> name.length() > 5);
    }


Good thing is Java 8 comes with many useful functional interfaces so that we do not need to create our own. Have a look at the documentation.

Above code can be re-written in Java 8 as below;


import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class Java8FirstApp {

    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("Apple", "Java Plums", "Mango", "Banana");

        test(fruits, (name) -> name.length() == 5);
        test(fruits, (name) -> name.length() > 5);
    }

    private static void test(List<String> names, Predicate<String> predicate) {
        for (String name : names) {
            if (predicate.test(name)) {
                System.out.printf("%s - test passed %n", name);
            }
        }
    }
}


clear and concise!!!


Java 8 - Lambda Expressions

Greetings!

Before Java8, Java is a fully object oriented programming language. While most of the other programming languages introduces functional programming Java was in OOP way. Java8 introduces lot of features and lambdas are the biggest change that happened to the language so far.

What is functional programming?

It is a programming style that allows to program using expressions. With that we can create instance of a function and assign to a variable, pass functions to methods as arguments.

Is OOP not enough?

We can do everything without lambda expressions. But it help us to write better readable and maintainable codes. And also it gives us better support of multi-cores.
In OOP we are not passing behaviors. We pass objects which have behaviors. In functional programming we can pass behaviors.

Benefits of lambda expressions

  • Parallel processing.
  • Enable functional programming.
  • Readable and concise.

Syntax

A lambda expression has 3 parts.
  • Argument list
  • Arrow token
  • Body

(arguments) -> { body }

  • For a single argument parenthesis are optional.
  • For a single line expressions, brackets are optional.
  • For a single line expressions, return statement can be omitted using brackets.
  • Parameter types are optional. Compiler can inference the type from the value. (type inference)