Java8 Syntax Refresher
Here is a non-exhaustive list of fundamental Java8 questions that tests Java8 FP/Declarative style coding. Some of them are one-liners, and they can be solved with pre-Java8 syntax as well, but the idea is to solve it with Java8 syntax. In this post I may have used some of the new constructs like records(A preview feature in Java14 and officially stable feature in Java16), string.chars()(since Java9) and others.
Queries
- Take first 10 integers(1 to 10)and return the sum of the squares of the even numbers in the list.
- Given a list of strings,
"Java", "C#", "Java", "Python", "C", "C++", "Python", "Java", "C++"
print the 3 most frequently occurring words.
- Find the most frequently occurring character in a string
"america"
- Given a list of strings,
"global", "warming", "is", "real", "prob"
return the list of strings that have exactly 4 characters.
- Consider an employee object with salary attribute, create a sample list of employees, calculate the average salary of the employees.
- Given a list of integers
25, 36, 75, 60
return the largest number that is less than the average of the numbers.
- Given a list of integers
2, 3, 7, 8, 9, 7, 5, 3, 2, 8
return a new list that contains unique elements from the given list.
- Assume an employee object with department attribute as String type, create a sample list of employees, return a list of departments that have at least 2 employees.
- Given a list of integers, return a new list that contains only the even numbers from the original list.
- reduction queries:
- Solve with reduce func: Given a list of integers
- reduce to sum
- reduce to product
- reduce to minimum
- reduce to maximum
- Given a list of strings, concatenate all strings
- Given a list of strings, find the total number of characters in a list of strings
- Find the longest string from the given list of strings. What if there is a tie? Get all the matching longest strings
- Given a list of employees with salary attribute, find the sum of salaries of all the employees.
- Solve with reduce func: Given a list of integers
Syntax refresher and common patterns
java.util.Arrays.asList(T... a)
- Returns a fixed size list backed by array
- You cannot add or remove elements to this list - Attempt to do that would result in
java.lang.UnsupportedOperationException
- Note:
java.util.Arrays.asList(T... a)
works with wrappers and objects not primitives-
Example:
int[] arr = {1, 2, 3, 4}; Arrays.asList(arr); // returns List<int[]>
Integer[] arr = {1,2,3,4}; Arrays.asList(arr); // returns List<Integer>
Arrays.asList(1,2,3,4); // returns List<Integer>
-
- Passing array of primitives like
int[]
toArrays.asList()
it returnsList<int[]>
as shown above. If in case we have to stream anint[]
usejava.util.Arrays.stream(int[])
.-
Example below
int[] x = {1,2,3,4}; List<Integer> ints = java.util.Arrays.stream(x) // converts int[] to IntStream .boxed() // convert IntStream to Stream<Integer> .collect(Collectors.toList()); // Collect Stream<Integer> to List<Integer>
-
Below are the overloaded methods versions of
java.util.Arrays.stream()
java.util.stream.DoubleStream java.util.Arrays.stream(double[] array) java.util.stream.DoubleStream java.util.Arrays.stream(double[] array, int startInclusive, int endExclusive) java.util.stream.IntStream java.util.Arrays.stream(int[] array) java.util.stream.IntStream java.util.Arrays.stream(int[] array, int startInclusive, int endExclusive) java.util.stream.LongStream java.util.Arrays.stream(int[] array) java.util.stream.LongStream java.util.Arrays.stream(int[] array, int startInclusive, int endExclusive) java.util.stream.Stream<T> java.util.Arrays.stream(T[] array) - /** Used for custom types like record Employee(){} Employee[] emps = {new Employee(), new Employee()}; Arrays.stream(emps); // returns java.util.stream.Stream<Employee> */
-
Solve all the below problems using Java8 FP/declarative style syntax
-
Take first 10 integers(1 to 10)and return the sum of the squares of the even numbers in the list.
- Assume the list is given
// Assume this as given input list List<Integer> ints = Arrays.asList(1, 2, 3, 4); int sum = ints.stream() .filter(x -> x % 2 == 0) .map(elm -> elm * elm) .collect(Collectors.summingInt(a -> a)); System.out.println(sum); // Prints 20
- Alternatively, if we have to assume and initialize the input
int sum = java.util.stream.IntStream.rangeClosed(1, 10) .boxed() .filter(x -> x % 2 == 0) .map(elm -> elm * elm) .collect(Collectors.summingInt(a -> a)); System.out.println(sum); // Prints 220
- Alternatively
int result = IntStream.rangeClosed(1, 10) .boxed() .filter(i -> i % 2 == 0) .mapToInt(elm -> elm * elm) .sum(); System.out.println(result);
- Note:
java.util.stream.IntStream
returns primitive int - So we have to useboxed()
to make it as wrapper. -
java.util.stream.IntStream.rangeClosed(startInclusive, endInclusive)
-
java.util.stream.IntStream.range(startInclusive, endExclusive)
-
Given a list of strings, print the 3 most frequently occurring words.
List<String> strings = Arrays.asList("Java", "C#", "Java", "Python", "C", "C++", "Python", "Java", "C++"); Map<String, Long> wordCount = strings .stream() .collect( Collectors.groupingBy(str -> str, Collectors.counting())); System.out.println(wordCount); // Prints {C#=1, Java=3, C++=2, C=1, Python=2} List<String> _3MostFrequentWords = wordCount .entrySet() .stream() .sorted(Comparator.comparing(entry -> entry.getValue(), (v1, v2) -> v2.compareTo(v1))) .limit(3) .map(entry -> entry.getKey()) .collect(Collectors.toList()); System.out.println(_3MostFrequentWords); // Prints [Java, C++, Python]
-
Find the most frequently occurring character in a string.
String x = "america"; Map<Character, Long> charCount = x.chars() // Since Java9 - returns IntStream .mapToObj(i -> (char) i)// returns Stream<Character> .collect(Collectors.groupingBy(c -> c, Collectors.counting())); System.out.println(charCount); Character result = charCount.entrySet().stream() .sorted( // sort by val in reverse order Comparator.comparing(entry -> entry.getValue(), (v1, v2) -> v2.compareTo(v1))) .limit(1) .map(entry -> entry.getKey()) .findFirst() .orElseThrow(); System.out.println(result);
-
Given a list of strings, return the list of strings that have exactly 4 characters.
List<String> strings = Arrays.asList("global", "warming", "is", "real", "prob");
-
Simple solution
List<String> result = strings .stream() .filter(x -> x.length() == 4) .collect(Collectors.toList()); System.out.println(result); // Prints [real, prob]
-
Alternatively
List<String> result = strings .stream() .collect(Collectors.groupingBy(str -> str.length())) .entrySet() .stream() .filter(entry -> entry.getKey() == 4) .map(entry -> entry.getValue()) .findFirst() .orElseThrow(); System.out.println(result); // Prints [real, prob]
-
-
Consider an employee object with salary attribute, create a sample list of employees, calculate the average salary of the employees.
record Employee(String name, double sal) {} List<Employee> employees = Arrays.asList( new Employee("srk", 87.5), new Employee("hero", 99.9)); double avgSalOfEmps = employees .stream() .mapToDouble(emp -> emp.sal) // returns DoubleStream .average() // returns OptionalDouble .getAsDouble(); System.out.println(avgSalOfEmps); // Prints 93.7
-
Given a list of integers, return the largest number that is less than the average of the numbers.
List<Integer> ints = Arrays.asList(25, 36, 75, 60); double avg = ints .stream() .mapToInt(i -> i) .average() .getAsDouble(); System.out.println(avg); // Prints 49.0 Double result = ints .stream() .mapToDouble(i -> i) .filter(num -> num < avg) .max() .getAsDouble(); System.out.println(result.intValue()); // Prints 36
-
Given a list of integers, return a new list that contains unique elements from the given list.
List<Integer> ints = Arrays.asList(2, 3, 7, 8, 9, 7, 5, 3, 2, 8); List<Integer> unqiueElems = ints.stream() .collect(Collectors.groupingBy(i -> i, Collectors.counting())) .entrySet() .stream() .filter(entry -> entry.getValue() == 1) .map(entry -> entry.getKey()) .collect(Collectors.toList()); System.out.println(unqiueElems); // Prints [5,9]
-
Assume an employee object with department attribute as String type, create a sample list of employees, return a list of departments that have at least 2 employees.
record Employee(String name, String department) {} List<Employee> emps = Arrays.asList( new Employee("srk", "IT"), new Employee("pull", "IT"), new Employee("jenny", "Finance"), new Employee("katly", "HR"), new Employee("Sujany", "HR")); // Return list of departments that have at least 2 employees List<String> departments = emps.stream().collect( Collectors.groupingBy(emp -> emp.department)) .entrySet() .stream() .filter(entry -> entry.getValue().size() >= 2) .map(entry -> entry.getKey()) .collect(Collectors.toList()); System.out.println(departments); // Prints [HR, IT]
-
Given a list of integers, return a new list that contains only the even numbers from the original list.
List<Integer> result = java.util.stream.IntStream .rangeClosed(1, 10) .boxed() .filter(x -> x % 2 == 0) .collect(Collectors.toList()); System.out.println(result); // Prints [2, 4, 6, 8, 10]
Solve the below using reduce function
- Given a list of integers
-
reduce to sum
-
int result = java.util.stream.IntStream .rangeClosed(1, 3) // returns IntStream .reduce((a, b) -> a + b) // returns OptionalInt .getAsInt(); System.out.println(result); // Prints 6
-
int result = java.util.stream.IntStream .rangeClosed(1, 3) .reduce(0, (a, b) -> a + b); System.out.println(result); // Prints 6
-
-
reduce to product
-
int result = java.util.stream.IntStream .rangeClosed(1, 3) .reduce((a, b) -> a * b) // returns OptionalInt .getAsInt(); System.out.println(result); // Prints 6
-
int result = java.util.stream.IntStream .rangeClosed(1, 3) .reduce(1, (a, b) -> a * b); System.out.println(result); // Prints 6
-
-
reduce to minimum
-
int result = java.util.stream.IntStream .rangeClosed(1, 3) .reduce((a, b) -> Math.min(a, b)) // returns OptionalInt .getAsInt(); System.out.println(result); // Prints 1
-
int result = java.util.stream.IntStream .rangeClosed(1, 3) .reduce(1, (a, b) -> Math.min(a, b)); System.out.println(result); // Prints 1
-
-
reduce to maximum
-
int result = java.util.stream.IntStream .rangeClosed(1, 3) .reduce((a, b) -> Math.max(a, b)) // returns OptionalInt .getAsInt(); System.out.println(result); // Prints 3
-
int result = java.util.stream.IntStream .rangeClosed(1, 3) .reduce(1, (a, b) -> Math.max(a, b)); System.out.println(result); // Prints 3
-
-
-
Given a list of strings, concatenate all strings
String[] strings = {"un", "ited"}; String result = java.util.Arrays.stream(strings) .collect(Collectors.joining()); System.out.println(result); // Prints "united"
-
Given a list of strings, find the total number of characters in a list of strings
-
List<String> strings = Arrays.asList("united", "states", "of", "america"); int charCount = strings .stream() .mapToInt(str -> str.length()) .sum(); System.out.println(charCount); // Prints 21
-
List<String> strings = Arrays.asList("united", "states", "of", "america"); int charCount = strings .stream() .collect(Collectors.joining()) .toCharArray() .length; System.out.println(charCount); // Prints 21
-
- Find the longest string from the given list of strings
- Note: What if there is a tie? Get all the matching longest strings
List<String> strings = Arrays.asList("united", "states", "of", "america"); List<String> result = strings .stream() .collect(Collectors.groupingBy(str -> str.length())) .entrySet() .stream() // .max(Comparator.comparing(entry -> entry.getKey())) // the above line also works .max(Comparator.comparingInt(entry -> entry.getKey())) .map(entry -> entry.getValue()) .orElseThrow(); // throws java.util.NoSuchElementException if No value is present System.out.println(result); // Prints [america]
-
Given a list of employees with salary attribute, find the sum of salaries of all the employees.
record Employee(String name, double sal) {} List<Employee> employees = Arrays.asList(new Employee("srk", 100), new Employee("hero", 200)); double sumOfSalaries = employees .stream() .mapToDouble(emp -> emp.sal) .sum(); System.out.println(sumOfSalaries); // Prints 300.0
SQL equivalents in Java8
Let’s consider a simple dataset of employee
table with cols name
, salary
, and department
name | salary | department |
Alice | 50000 | HR |
Bob | 70000 | Finance |
Charlie | 60000 | HR |
Dave | 90000 | Finance |
Steve | 80000 | HR |
- SQL: Example of GROUP BY the employees by department and calculate the total salary for each department
SELECT department, SUM(salary) FROM employees GROUP BY department;
Java8
List<Employee> emps = Arrays.asList( new Employee("Alice", 50000, "HR"), new Employee("Bob", 70000, "Finance"), new Employee("Charlie", 60000, "HR"), new Employee("Dave", 90000, "Finance"), new Employee("Steve", 80000, "HR") Map<String, Integer> totalSalariesByDept = employees .stream() .collect(Collectors.groupingBy( Employee::getDepartment, Collectors.summingInt(Employee::getSalary))); )
- SQL
SELECT * FROM employee WHERE salary > 5000 ORDER BY name ASC;
Java8
List<Employee> emps = employees .stream() .filter(emp -> emp.getSalary() > 5000) .sorted(Comparator.comparing(emp -> emp.getName())) .collect(Collectors.toList());
- SQL
SELECT COUNT(*) FROM employee;
Java8
long count = employees .stream() .count();
- SQL
SELECT DISTINCT department FROM employee;
Java8
List<String> departments = employees .stream() .map(emp -> emp.getDepartment()) .distinct() // removes duplicates .collect(Collectors.toList());
- SQL
SELECT MAX(salary) FROM employee;
Java8
double maxSal = employees .stream() .map(emp -> emp.getSalary()) .max()// returns OptionalDouble .getAsDouble();
- SQL
SELECT * FROM employee WHERE name LIKE ‘J%’;
Java8
List<Employee> filteredEmps = employees .stream() .filter(emp -> emp.getName().startsWith("J")) .collect(Collectors.toList());
- SQL
SELECT * FROM employee WHERE department IN (‘IT’, ‘Finance’);
Java8
List<Employee> filteredEmps = employees .stream() .filter(emp -> emp.getDepartment().equals("IT") || emp.getDepartment().equals("Finance")) .collect(Collectors.toList());
- SQL
SELECT name, salary FROM employee WHERE salary BETWEEN 40000 AND 60000;
Java8
Map<String, Double> nameSalMap = employees .stream() .filter(emp -> emp.getSalary() >= 4000 && emp.getSalary() <= 6000) .collect(Collectors.toMap(emp -> emp.getName(), emp -> emp.getSalary()));
- SQL
SELECT AVG(salary) FROM employee WHERE department = ‘Sales’;
Java8
double avgSal = employees .stream() .filter(emp -> emp.getDepartment().equals("Sales")) .mapToDouble(emp -> emp.getSalary()) .average() // returns OptionalDouble .getAsDouble();
- SQL
SELECT * FROM employee WHERE hire_date >= ‘2022-01-01’ AND hire_date <= ‘2022-12-31’
Java8
List<Employee> emps = employees .stream() .filter( emp -> emp.getHireDate().isAfter(LocalDate.of(2022,1,1)) && emp.getHireDate().isBefore(LocalDate.of(2022, 12, 31))) .collect(Collectors.toList())
-
SQL
SELECT COUNT(*) FROM employee GROUP BY department;
Java8
Map<String, Long> employeeCountByDepartment = employees .stream() .collect( Collectors.groupingBy( emp -> emp.getDepartment(), Collectors.counting()));