Let’s look into the group by operation provided by Java 8 for grouping elements together. It is similar to the one provided by SQL.
import java.util.*;
import java.util.stream.*;
import java.util.function.Function;
public class MyClass {
public static void main(String args[]) {
List<String> items = Arrays.asList("apple","guava","banana","apple","guava","orange","banana","apple");
Map<String,Long> result = items.stream().collect(Collectors.groupingBy(Function.identity(),Collectors.counting()));
System.out.println("The count of all fruits are as follows : "+result);
}
}
So if you see above, the fruits were grouped by their respective counts.
Let’s group by using Objects.
Here we are grouping by the student name to find his total points scored in all the rounds.
import java.util.*;
import java.util.stream.*;
class Student {
private String name;
private int round;
private int points;
public Student(String name, int round, int points) {
super();
this.name = name;
this.round = round;
this.points = points;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getRound() {
return round;
}
public void setRound(int round) {
this.round = round;
}
public int getPoints() {
return points;
}
public void setPoints(int points) {
this.points = points;
}
}
public class Java8GroupByExample {
public static void main(String args[]) {
List<Student> studList = Java8GroupByExample.createStudList();
Map<String,Integer> studPoints =
studList.stream().collect(Collectors.groupingBy(Student::getName,Collectors.summingInt(Student::getPoints)));
System.out.println("Grouped by student total points : "+studPoints);
}
public static List<Student> createStudList()
{
List<Student> studList=new ArrayList<Student>();
Student s1=new Student("Nathan",1,500);
Student s2=new Student("Nathan",2,1200);
Student s3=new Student("Nathan",3,1500);
Student s4=new Student("Chris",1,1000);
Student s5=new Student("Chris",2,2000);
Student s6=new Student("Chris",3,200);
Student s7=new Student("David",1,100);
Student s8=new Student("David",2,1000);
Student s9=new Student("David",3,500);
Student s10=new Student("James",1,300);
Student s11=new Student("James",2,2600);
Student s12=new Student("Mike",1,3000);
studList.add(s1);
studList.add(s2);
studList.add(s3);
studList.add(s4);
studList.add(s5);
studList.add(s6);
studList.add(s7);
studList.add(s8);
studList.add(s9);
studList.add(s10);
studList.add(s11);
studList.add(s12);
return studList;
}
}
allMatch, anyMatch and noneMatch methods introduced in Java 8 can be used with Lambda Expressions to find if any word or letter exists in a list of strings or not.
Kindly check the below code to see the behavior of the 3 methods.
import java.util.*;
import java.util.stream.*;
public class Java8MatchExample {
public static void main(String args[]) {
List<String> namesList = Java8MatchExample.getNamesList();
boolean respMatch = namesList.stream().allMatch(n->n.contains("z"));
if(respMatch==true){
System.out.println("All words contain z");
}
else{
System.out.println("Not all words contain z");
}
boolean respAnyMatch = namesList.stream().anyMatch(n->n.contains("z"));
if(respAnyMatch==true){
System.out.println("Atleast one word contains z");
}
else{
System.out.println("None of the words contain z");
}
boolean respNoneMatch = namesList.stream().noneMatch(n->n.contains("y"));
if(respNoneMatch==true){
System.out.println("None of the words contains y");
}
else{
System.out.println("One or more words contain y");
}
}
private static List<String> getNamesList(){
List<String> list = new ArrayList<String>();
list.add("nathan");
list.add("chris");
list.add("david");
list.add("james");
list.add("mike");
list.add("zack");
return list;
}
}
In the below example, you will see how to use the distinct operation on a list of elements to fetch the list of all distinct elements.
If the elements is a Custom User Class, then we would need to override the equals and hashCode method as there would be a need to correctly check for equality of 2 objects.
Kindly find the below code.
import java.util.*;
import java.util.stream.*;
class Student {
private String name;
private int empId;
public Student(String name, int empId) {
super();
this.name = name;
this.empId = empId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return empId;
}
public void setId(int empId) {
this.empId = empId;
}
@Override
public boolean equals(Object o)
{
if(this == o)
return true;
if(o == null || o.getClass()!= this.getClass())
return false;
Student st = (Student) o;
return (st.getName().equals(this.getName()) && st.getId() == this.getId());
}
@Override
public int hashCode()
{
return 1;
}
}
public class Java8DistinctExample {
public static void main(String args[]) {
List<Integer> numList = Java8DistinctExample.getNumList();
List<Integer> distinctList = numList.stream().distinct().collect(Collectors.toList());
System.out.println("Distinct elements : "+distinctList);
List<Student> studList = Java8DistinctExample.createStudList();
List<Student> distinctStudList = studList.stream().distinct().collect(Collectors.toList());
System.out.println("Distinct student objects : "+distinctStudList);
}
private static List<Integer> getNumList(){
List<Integer> list = new ArrayList<Integer>();
list.add(10);
list.add(10);
list.add(102);
list.add(109);
list.add(122);
list.add(134);
list.add(134);
list.add(148);
return list;
}
public static List<Student> createStudList()
{
List<Student> studList=new ArrayList<Student>();
Student s1=new Student("Aalo",215013);
Student s2=new Student("Aalo",215013);
Student s3=new Student("Sumo",215012);
Student s4=new Student("Shiji",222432);
Student s5=new Student("Lufo",310131);
Student s6=new Student("Lufo",310131);
Student s7=new Student("Zishi",310135);
studList.add(s1);
studList.add(s2);
studList.add(s3);
studList.add(s4);
studList.add(s5);
studList.add(s6);
studList.add(s7);
return studList;
}
}
Below is the source code for merging 2 HashMaps. Keys would be same in both maps. Values may or may not be same. If values are same for a particular key, distinct value would be shown in the final merged map. If different, it would be concatenated comma separated.
import java.util.*;
import java.util.stream.*;
public class Java8MapMerge {
public static void main(String args[]) {
HashMap<Integer,String> map1 = new HashMap<>();
map1.put(1,"A");
map1.put(2,"B");
map1.put(3,"C");
map1.put(5,"E");
HashMap<Integer,String> map2 = new HashMap<>();
map2.put(1,"G");
map2.put(2,"B");
map2.put(3,"C");
map2.put(4,"D");
map2.forEach((key,value) -> map1.merge(key,value,(v1,v2)->v1.equalsIgnoreCase(v2)?v1:v1+","+v2));
System.out.println(map1);
}
}
Compared to the java.util.date API, the new date API’s are immutable and thread safe. Alos it has a lot of new features and methods compared to it’s previous counterpart.
API’s introduced in Java 8 are:
LocalDate
LocalTime
LocalDateTime
import java.time.*;
public class MyClass {
public static void main(String[] args) {
//current date
LocalDate date = LocalDate.now();
System.out.println("Current date is "+
date);
// current time
LocalTime time = LocalTime.now();
System.out.println("Current time is "+
time);
// current time and date
LocalDateTime current = LocalDateTime.now();
System.out.println("Current date and time : "+
current);
// To format a date into a particular type
DateTimeFormatter format =
DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
String formattedDate = current.format(format);
System.out.println("Formatted date is "+
formattedDate);
//Get month,day from current date time
Month month = current.getMonth();
int day = current.getDayOfMonth();
System.out.println("Month : "+month+" day : "+
day);
}
}
As seen above, you can see the usage of a method reference. The println method of System.out object is applied to each element of the List. You can see the List printed above.
Let’s take an example involving a Custom Class and using method reference with it.
import java.util.*;
import java.util.stream.*;
class Student {
private String name;
private int empId;
public Student(String name, int empId) {
super();
this.name = name;
this.empId = empId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return empId;
}
public void setId(int empId) {
this.empId = empId;
}
}
public class MyClass {
public static void main(String[] args)
{
List<Student> studList = createStudList();
List l = studList.stream().map(Student::getName).collect(Collectors.toList());
System.out.println(l);
}
public static List<Student> createStudList()
{
List<Student> studList=new ArrayList<Student>();
Student s1=new Student("Sumo",21);
Student s2=new Student("Shiji",22);
Student s3=new Student("Lufo",31);
studList.add(s1);
studList.add(s2);
studList.add(s3);
return studList;
}
}
Here we iterated over the list containing student objects and calling the getName method by method reference for each element, we mapped it to name and collected it into a list.
Let’s take another example.
import java.util.function.*;
class Addition{ public static int add(int a, int b){ return a+b; } } public class MyClass { public static void main(String[] args) { BiFunction addFunction = Addition::add; int output = addFunction.apply(100, 200); System.out.println(output); } }
We used a Java 8 Function Interface here to add 2 numbers.