Java Streams

Playing with Collection & Map in Function

May 17, 2020

Hello Friends! Welcome back.

Modern java libraries have changed a lot since Java 1.8. Collections libraries got impacted and changed a lot since then. We can say that Collections are the biggest beneficiaries of Functional paradigm. In modern Java, collection uses functional programming style a lot and libraries have changed accordingly.

In this blog we will focus upon Collections and how we can use them in Modern Java prospective using functional programming; things like how to iterate them, how to extract elements from them, how to sort them and many more operations of manipulating collections in a functional way, as functional programming makes the code more readable, expressive and concise.’

In the coming sections, we will discuss the different collections.

LIST

List is a the most widely used linear data structure. Here, we’ll implement the basic operations that we do with list but in functional way:

  • traversing of list, which we generally do using classic for loop or enhanced for loop
  • searching for an element or filtering elements, which we do, while iterating list using any conditional statements
  • sorting of elements
  • mapping elements to some other value or transforming the collection
  • reducing list into a single value

Let us take an example. This is a movies list consisting of the movie name, year of its release and the industry to which it belongs.

public class ListFunctional {

	public static void main(String[] args) {
		List<Movie> movies = Arrays.asList(
				new Movie("Spotlight",2015,"Hollywood"),
				new Movie("Avengers: Infinity War",2018,"Hollywood"),
				new Movie("Inception",2010,"Hollywood"),
				new Movie("Forest Gump",1994,"Hollywood"),
				new Movie("3 Idiots",2009,"Bollywood"),
				new Movie("Beauty and the beast",2017,"Hollywood"),
				new Movie("Slumdog Millionaire",2008,"Bollywood")
				);
	}
}

We have already created its implementation with constructors, get & set functions etc.

public class Movie{

     private String name;
     private int release year;
     private String industry;

     public Movie(String name, int releaseYear, String industry) {
          this.setName(name);
          this.setReleaseYear(releaseYear);
          this.setIndustry(industry);
     }

     public String getName() {
          return name;
     }

     public void setName(String name) {
          this.name = name;
     }

     public int getReleaseYear() {
          return releaseyear;
     }

     public void setReleaseYear(int releaseYear) {
          this.releaseYear = releaseYear;
     }

     public String getIndustry() {
          return industry;
     }

     public void setIndustry(String industry) {
          this.industry = industry;
     }

     @Override
     public String toString() {
          return "movie [name=" + name + ", releaseYear=" + releaseYear + ", industry=" + industry + "];
     }
}

List Traversal

The first operation that we will perform is list traversal. The details of all the movies will be displayed in the output if we run the below code.

movies.forEach(System.out::println);  

The next operation that we will perform is sorting. It will display all the movies sorted according to their release year in the output if we run the below code.

movies.sort(o1, o2) -> o2.getReleaseYear()-o1.getReleaseYear());
movies.forEach(System.out::println);  

Filtering

The next operation that we will perform is filtering. It will display all the movies belonging to the industry Bollywood in the output if we run the below code.

movies.stream()
     .filter(movie -> movie.getIndustry().equalsIgnoreCase("Bollywood"))
     .forEach(System.out::println);

Mapping

The next operation is mapping. It will display names of all the movies in the output if we run the below code.

movies.stream()
     .map(movie -> movie.getname())
     .forEach(System.out::println);

Reduce

The last operation is reduce. It will display names of all the movies separated by a pipe (|) in the output if we run the below code.

Optional<String> moviesString = movies.stream()
     .map(m -> m.getname())
     .reduce(m1,m2) -> m1+" | "+m2);
System.out.println(moviesString);

So, these were the basic operations on a list in a functional way.

SET

In this section, we will try the same basic operations on a set. First we will create a set.

public class SetFunctionalOperations {

	public static void main(String[] args) {
        	Set<Integer> set = Set.of(3,56,7,82,39);
	}
}

The first operation is traversal. All the numbers of the set will be displayed in the output.

set.forEach(System.out::println);

Output:
39
56
3
82
7

The next operation is filter. All the even numbers will be displayed in the output.

set.stream()
     .filter(e -> e%2 == 0)
     .forEach(System.out::println);

Output:
56
82

The next operation is sorting. All the numbers will be displayed in the sorted order in the output.

set.stream()
     .sorted()
     .forEach(System.out::println);

Output:
3
7
39
56
82

The next operation is map. All the numbers will be displayed in double in the output.

Set<Double> hashset = set.stream()
     .map(e -> Double.valueOf(e))
     .collect(Collectors.toSet());
hashset.forEach(System.out::println);

Output:
39.0
82.0
3.0
7.0
56.0

The next operation is reduce. The sum of all the numbers will be displayed in the output.

int sum = set.stream()
     .mapToInt(e -> e)
     .sum();
System.out.println(sum);

Output:
187

MAP

In this section, we will try the same basic operations on a map. First we will create a class.

public class MapFunctionalOperations {

	public static void main(String[] args) {

		Map<String,String> contacts = new HashMap<>();
		                                                      contacts.put("1237589020", "John");
		                                                      contacts.put("1237009020", "John");
		                                                      contacts.put("7890291111", "Neal");
		                                                      contacts.put("2647210290", "Raju");
		                                                      contacts.put("9999999999", "Peter");
		                                                      contacts.put("9081234567", "Neha");

	}

}

The first operation is traversal. The contact number and name of all the persons will be displayed in the output.

for(Map.Entry<String, String> entry : contacts.entrySet()) {
     System.out.println(entry.getKey() + " - "+ entry.getvalue());
} 
contact.forEach(k, v) -> System.out.println(k +" - "+v));

Output:
1237589020 – John
1237009020 – John
7890291111 – Neal
2647210290 – Raju
9999999999 – Peter
9081234567 – Neha

The next operation is filter. The contact number and name of only John will be displayed in the output.

contacts.entrySet().stream()
     filter(contact -> "John".equalsIgnoreCase(contact.getValue()))
     .forEach(System.out::println);

Output:
1237589020 – John
1237009020 – John

The next operation is map. All the names will be displayed in a string in the output.

String contactNames = contacts.entrySet().stream()
     .distinct()
     .map( c -> c.getValue())
     .collect(Collectors.joining(" , "));

System.out.println(contactNames);

Output:
John, Neal, Neha, Raju, John, Peter

The next operation is sorting. All the names will be displayed in a sorted order along with their respective contact numbers in the output.

LinkedHashMap<String, String> sortedMap = contacts.entrySet().stream()
     .sorted(Entry.comparing.By.Value())
     .collect(Collectors.toMap(c -> c.getKey(). c -> c.getValue(), (v1, v2) -> v1, LinkedHashMap::new));

sortedMap.forEach(k, v) -> Sytsem.out.println(k+" - "+v));

Output:
1237589020 – John
1237009020 – John
7890291111 – Neal
9081234567 – Neha
9999999999 – Peter
2647210290 – Raju

The last operation is reduce. The average marks of all the subjects will be displayed in the output.

Map<String, Double> marks = new HashMap<>();
marks.put("Science", 66.00);
marks.put("Maths", 78.00);
marks.put("English", 90.00);

OptionalDouble average = marks.value().stream()
     .mapToDouble(m -> m)
     .average();

System.out.println(average.getAsDouble());

Output:
78.0

SUMMARY

To summarize, we discussed three collections – list, set & map and five operations for each of them – traverse, filter, sort, map & reduce.