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)));