Streams

Source

  • Array, Collection, generator function, I/O channel
  • Primitive Streams
    • IntStream
    • LongStream
    • DoubleStream
  • Boxing and Unboxing
int[] nums = {4, 3, 7, 8, 1};
// boxing
List<Integer> numbers = Stream.of(nums).boxed().toList();
 
// unboxing
int[] finalNums = numbers.mapToInt(n -> n).toArray();

Intermediate vs Terminal Operators

Collectors

  • .groupingBy(keyMapper)
  • .groupingBy(keyMapper, Collector)
  • .toList()
  • .toSet()
  • .toMap()
  • .joining(delimiter) — String case
  • .reducing(T, BinaryOperator)
  • .collectingAndThen(Collector)
  • .counting()
  • .minBy(Comparator)
  • .maxBy(Comparator)
  • Sum
    • summingInt(mapper)
    • summingLong(mapper)
    • summingDouble(mapper)
  • Average
    • averagingInt(mapper)
    • averagingLong(mapper)
    • averagingDouble(mapper)
  • Summary
    • summarizingInt(mapper)
    • summarizingLong(mapper)
    • summarizingDouble(mapper)
    • methods:
      • average, count, sum, min, max

Sum and avg. of all the integers

int[] nums = {4, 3, 7, 8, 1};
System.out.println(Arrays.stream(nums).sum()); // IntStream.count()
 
List<Integer> numbers = Arrays.stream(nums) // IntStream to List
        .boxed()
        .toList();
 
// Using mapToInt()
numbers.stream()
        .mapToInt(n -> n).sum();
 
// Using Collectors.summingInt()
numbers.stream()  
        .collect(Collectors.summingInt(n -> n));
 
// Avg
numbers.stream()
    .mapToDouble(Integer::doubleValue) // !important
    .average()
    .orElse(0.0);

String based

// Uppercase all strings
var names = Arrays.asList("Sachin", "manisH", "Suresh");
final List<String> uppercaseNames = names.stream()
    .map(String::toUpperCase)
    .toList();
 
// count of strings with length > 5
List<String> list = new ArrayList<>(List.of("he", "hello", "kiamotors", "helloworld", "hd"));
long count = list.stream().filter(e -> e.length() > 5).count();

Data Setup

@Getter
@Setter
@AllArgsConstructor
class Employee {
    private int id;
    private String name;
    private int age;
    private String departNames;
    private String address;
    private double salary;
    private String gender;
}
 
List<Employee> employees = Arrays.asList(
    new Employee(1, "Abraham", 29, "IT", "Mumbai", 20000, "Male"),
    new Employee(2, "Mary", 27, "Sales", "Chennai", 25000, "Female"),
    new Employee(3, "Joe", 28, "IT", "Chennai", 22000, "Male"),
    new Employee(4, "John", 29, "Sales", "Gurgaon", 29000, "Male"),
    new Employee(5, "Liza", 25, "Sales", "Bangalore", 32000, "Female"),
    new Employee(6, "Peter", 27, "Admin", "Mumbai", 31500, "Male"),
    new Employee(7, "Harry", 30, "Research", "Kochi", 21000, "Male")
);

Max age of employees

employees.stream()  
        .mapToInt(Employee::getAge)  
        .max().orElse(-1);

Count of employee in each department

employees.stream().collect(
    Collectors.groupingBy(Employee::getDepartment, Collectors.counting())
);

Second Lowest/Highest Salary

var secondLowestSalaryEmployee = employees.stream()
        .sorted(Comparator.comparing(Employee::getSalary))
        .skip(1)
        .findFirst().orElse(null);
 
var secondHighestSalaryEmployee = employees.stream()
        .sorted(Comparator.comparing(Employee::getSalary).reversed())
        .skip(1)
        .findFirst().orElse(null);

Department with maximum number of employees

employees.stream()
                .collect(Collectors.groupingBy(
                                Employee::getDepartment,
                                Collectors.counting()))
                .entrySet().stream()
                .max(Comparator.comparingLong(Map.Entry::getValue))
                .map(Map.Entry::getKey).orElse(null);

Average age of each gender

employees.stream()  
        .collect(Collectors.groupingBy(  
                Employee::getGender,  
                Collectors.averagingInt(Employee::getAge)  
        ));

Find first non-repeating character using streams

String str = "karnataka";
List<String> characters = Arrays.asList(str.split(""));
Map<String, Long> freq = characters.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
String result = characters.stream()
        .filter(c -> freq.get(c).equals(1L)) // compare with Long else will fail
        .findFirst().orElse(null);
 
System.out.println(freq);
System.out.println(result);
  • Optimized using LinkedHashMap
    • It remembers the insertion order
String result = characters.stream()
        .collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()))
        .entrySet().stream()
        .filter(entry -> entry.getValue() == 1L)
        .map(entry -> entry.getKey())
        .findFirst().orElse(null);
 
System.out.println(result);