Skip to main content

Collection & Streams

Story behind Collection

Handling large number of objects situation is not new in Java. Even when Java first introduced we have Vector, HastTable classes to work with Collection of objects.

But on that time importance were given to multi-threading than efficiency.

So by default HastTable and Vector classes are synchronized and are thread safe. In order to achieve thread safe they compromised in performance. Later they figured performance matters than thread safety in Collection.

Java 1.2 and Collection rebirth

So a complete new set of classes and interfaces were introduced in Java 1.2 to redefine the way Java deals with collection.

On top of it we have a number of interfaces developed for collection.

Collection interface is the primary interface (with add, addAll, iterator methods) which declares basic definition to work with any collection.

Java introduced 4 important data structures to deal with collection of objects such as List, Set, Map, Queue (though the first three are widely used).

List, Set, Queue are interfaces extending collection interface but map interface doesnot extends collection interface.

List

List is ordered and will allow duplicates

List implementation classes

ArrayList

Uses Java Array behind the scences. It stores data in insertion order. Best if we are going to perform more read operation. For accessing any element in the ArrayList irrespective of the position, ArrayList consumes same time.

LinkedList

Uses Doubly Linked List Data Structure behind the scences. (Second node have pointer to first and third elements and so on). Stores data in insertion order. Best if we have more insertion and deletion operation.

Set

Set wont allow duplicates

Set implementation classes

HashSet

Stores data in a random order (unpredictable). HashSet uses Hashing algorithm in back end. It can only store unique elements. Best for addition.

TreeSet

Stores data in sorted order (ascending).

Uses Red Black Tree algorithm in back end. Stores only unique elements. Best for frequent read/write operation.

LinkedHashSet

Uses LinkedList and HashSet in back end. Stores unique elements but in insertion order.

Map

Everything is stored as key value pair (both key and value are Objects). Keys are unique. One key mapped to one value.

Important Map methods: put(), get(), keySet(), entrySet()

Concrete implementation classes

Map provides three implementation classes such as HashMap, TreeMap, LinkedHashMap. Character of all the three classes are same as HashSet, TreeSet, LinkedHashSet.

HashMap - Keys are stored in Random order

TreeMap - Keys are sorted in natural order

LinkedHashSet - Keys are stored in insertion order.

Map is not part of collection why?

It is part of the collection framework but it doesn't implement the java.util.Collection interface. The Collection interface is implemented by (is the root of) List-like Collections while Map is implemented by (is the root of) the KEY-VALUE-like collections

Collections class

Collections class is a utility class which has number of static methods to help developers operate on Collection data structure in easier way. Few methods available with Collections class are as follow

sort(), max(), min(), reverseOrder(), shuffle()

Java 8 Streams API

public class Employee {

Integer grade;
String name;
Integer age;

// getters and setters
}

Data Setup

List<Employee> employeeList = new ArrayList<>();
employeeList.add(new Employee(3, "Vicky", 25));
employeeList.add(new Employee(3, "Dinesh", 22));
employeeList.add(new Employee(3, "Ganesh", 24));
employeeList.add(new Employee(1, "Ravi", 34));
employeeList.add(new Employee(1, "Sathappan", 33));
employeeList.add(new Employee(2, "Meenakshi", 31));
employeeList.add(new Employee(2, "Mahesh", 30));

Stream Samples


Map<Integer, List<Employee>> employeeGradeMap = employeeList.stream()
.collect(Collectors.groupingBy(Employee::getGrade));

Map<Integer, List<String>> employeeNameListGroupedByGrade = employeeList.stream()
.collect(Collectors.groupingBy(Employee::getGrade,
Collectors.mapping(Employee::getName, Collectors.toList())));

Map<Integer, List<Integer>> employeeAgeListGroupedByGrade = employeeList.stream()
.collect(Collectors.groupingBy(Employee::getGrade,
Collectors.mapping(Employee::getAge,
Collectors.toList())));

Map<Integer, Long> employeeCountAsLongBasedOnGrade = employeeList.stream()
.collect(Collectors.groupingBy(Employee::getGrade,
Collectors.counting()));

Map<Integer, Integer> employeeCountAsIntegerBasedOnGrade = employeeList.stream()
.collect(Collectors.groupingBy(Employee::getGrade,
Collectors.collectingAndThen(Collectors.counting(),
Long::intValue)));