Understanding Java Stream API: filter, map, flatMap, and Parallel Operations

This article explains how Java's Stream API enables efficient data processing through pipeline operations such as filter, map, flatMap, stream creation methods, conversion to collections, and parallel execution, providing code examples and practical usage guidelines.

Architect's Tech Stack
Architect's Tech Stack
Architect's Tech Stack
Understanding Java Stream API: filter, map, flatMap, and Parallel Operations

The article introduces Java's Stream API as a powerful way to process data in a pipeline, improving efficiency and unifying functional programming across languages.

filter operation : Demonstrates filtering a list of maps to retain entries with a non‑null, non‑empty "ip" field, then processing each element.

list.stream().filter(smap -> null != smap.get("ip") && !"".equals(smap.get("ip"))).forEach(imp -> {
    listipzone.add(wry.findIP(imp.get("ip").toString()));
});

map operation : Shows how map transforms each element, changing the generic type of the resulting stream.

String[] dd = { "a", "b", "c" };
Stream<String> stream = Arrays.stream(dd);
stream.filter(str -> str.equals("a")).forEach(System.out::println);

Another example converts Integer values to String and extracts the name field from a custom Emp object.

public static void main(String[] args) {
  Integer[] dd = {1, 2, 3};
  Stream<Integer> stream = Arrays.stream(dd);
  stream.map(str -> Integer.toString(str)).forEach(str -> {
    System.out.println(str);
    System.out.println(str.getClass());
  });

  List<Emp> list = Arrays.asList(new Emp("a"), new Emp("b"), new Emp("c"));
  list.stream().map(emp -> emp.getName()).forEach(str -> {
    System.out.println(str);
  });
}

public class Emp {
  private String name;
  public Emp() { super(); }
  public Emp(String name) { super(); this.name = name; }
  public String getName() { return name; }
  public void setName(String name) { this.name = name; }
}

flatMap operation : Explains that flatMap receives a function returning a Stream and flattens nested streams into a single stream.

public static void main(String[] args) {
  String[] strs = {"aaa", "bbb", "ccc"};
  Arrays.stream(strs).map(str -> str.split(""))
        .forEach(System.out::println);
  Arrays.stream(strs).map(str -> str.split(""))
        .flatMap(Arrays::stream)
        .forEach(System.out::println);
  Arrays.stream(strs).map(str -> str.split(""))
        .flatMap(str -> Arrays.stream(str))
        .forEach(System.out::println);
}

Common ways to create streams include Stream.of, Arrays.stream, and collection .stream() methods, with examples of converting arrays and lists into streams.

Stream stream = Stream.of("a", "b", "c");
String[] strArray = new String[]{"a", "b", "c"};
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
List<String> list = Arrays.asList(strArray);
stream = list.stream();

Converting streams to other data structures shows how to collect results into arrays, lists, sets, stacks, strings, and maps using Collectors.

// Array
String[] strArray1 = stream.toArray(String[]::new);
// Collection
List<String> list1 = stream.collect(Collectors.toList());
List<String> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
Set<String> set1 = stream.collect(Collectors.toSet());
Stack<String> stack1 = stream.collect(Collectors.toCollection(Stack::new));
// String
String str = stream.collect(Collectors.joining());
// Map grouping
Map<Integer, String> factoryMap = factoryConfigDOS.stream()
    .collect(Collectors.groupingBy(AgencyDailySalaryFactoryConfigDO::getFenceId,
        Collectors.mapping(AgencyDailySalaryFactoryConfigDO::getFactoryName, joining(","))));
// Map conversion with duplicate keys handling
Map<String, String> nameMap = incumbentExcelInfoList.stream()
    .collect(Collectors.toMap(info -> info.getIdCard(), info -> info.getName(), (k1, k2) -> k2));

It emphasizes that a Stream can be consumed only once, and that many APIs follow this pattern, which is valuable for big‑data processing and cross‑language compatibility.

The article lists intermediate operations (e.g., map, filter, distinct, sorted, peek, limit, skip, parallel) and terminal operations (e.g., forEach, toArray, reduce, collect, min, max, count, anyMatch, findFirst).

limit/skip example demonstrates extracting a sublist after limiting and skipping elements.

List<String> personList2 = persons.stream()
    .map(Person::getName)
    .limit(10)
    .skip(3)
    .collect(Collectors.toList());
System.out.println(personList2);

Finally, the article covers parallel streams: calling parallel() on an existing stream or using parallelStream() on a collection enables data parallelism across CPU cores.

int sumSize = Stream.of("Apple", "Banana", "Orange", "Pear")
    .parallel()
    .map(s -> s.length())
    .reduce(Integer::sum)
    .get();
assertEquals(sumSize, 21);
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javafunctional programmingStream APIParallelism
Architect's Tech Stack
Written by

Architect's Tech Stack

Java backend, microservices, distributed systems, containerized programming, and more.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.