Stream API Tutorial

Convert Java Data Types To Streams

A stream is a pipeline over data. If the data type already owns elements, like a List or Set, call .stream(). If the data is not a collection object, like an array, string, file, iterator, or nullable value, use a helper such as Arrays.stream(...), Stream.of(...), Files.lines(...), or StreamSupport.stream(...).

Why sometimes .stream() and sometimes Stream.of(...)?

Use data.stream() when the object implements Collection, such as List, Set, or Queue. Use utility methods when the value itself does not have a stream method.

// Collection owns stream()
employees.stream()

// Array does not have stream()
Arrays.stream(numbers)

// Individual values become a stream
Stream.of("IT", "HR", "Finance")

// One nullable object becomes 0 or 1 stream item
Stream.ofNullable(employee)

List / ArrayList / LinkedList

All lists implement Collection, so use .stream().

List<Employee> employees = new ArrayList<>();

List<String> names = employees.stream()
    .map(Employee::getName)
    .collect(Collectors.toList());

Set / HashSet / TreeSet

Sets also implement Collection. Stream order depends on the set type.

Set<String> departments = Set.of("IT", "HR", "Finance");

departments.stream()
    .filter(d -> d.length() > 2)
    .forEach(System.out::println);

Queue / Deque

Queues are collections too. Use stream when you want processing without removing items.

Queue<Integer> queue = new ArrayDeque<>();

int total = queue.stream()
    .mapToInt(Integer::intValue)
    .sum();

Object Array

Arrays do not have .stream(). Use Arrays.stream(array).

Employee[] employeeArray = {
    new Employee(101, "John", "IT", 70000)
};

Arrays.stream(employeeArray)
    .map(Employee::getName)
    .forEach(System.out::println);

Primitive Arrays

Primitive arrays become primitive streams: IntStream, LongStream, or DoubleStream.

int[] salaries = {70000, 50000, 90000};

int max = Arrays.stream(salaries)
    .max()
    .orElse(0);

Varargs / Fixed Values

Use Stream.of(...) when values are listed directly.

Stream.of("John", "Alice", "Bob")
    .map(String::toUpperCase)
    .forEach(System.out::println);

HashMap / LinkedHashMap

A map is not a collection of values directly. Stream entries, keys, or values.

Map<String, Integer> deptCount = new HashMap<>();

deptCount.entrySet().stream()
    .filter(e -> e.getValue() > 1)
    .forEach(System.out::println);

Map Keys / Values

Use keySet() for keys and values() for values.

map.keySet().stream()
    .forEach(System.out::println);

map.values().stream()
    .forEach(System.out::println);

String Characters

chars() creates an IntStream of character codes.

String name = "Stream";

name.chars()
    .mapToObj(c -> (char) c)
    .forEach(System.out::println);

String Words

Split the string, then stream the array.

String sentence = "Java stream api practice";

Arrays.stream(sentence.split("\\s+"))
    .filter(word -> word.length() > 4)
    .forEach(System.out::println);

Single Object

Use Stream.of(object) for one non-null object.

Employee employee = new Employee(101, "John", "IT", 70000);

Stream.of(employee)
    .map(Employee::getName)
    .forEach(System.out::println);

Nullable Object

Use Stream.ofNullable(...) so null becomes an empty stream.

Employee employee = findEmployee();

Stream.ofNullable(employee)
    .map(Employee::getName)
    .forEach(System.out::println);

Optional

Java 9+ has optional.stream(), useful for flattening optionals.

Optional<Employee> optional = findById(101);

optional.stream()
    .map(Employee::getDepartment)
    .forEach(System.out::println);

Nested List

Use flatMap to convert nested streams into one stream.

List<List<String>> skills = List.of(
    List.of("Java", "SQL"),
    List.of("Spring", "Java")
);

List<String> flat = skills.stream()
    .flatMap(List::stream)
    .distinct()
    .collect(Collectors.toList());

File Lines

Use Files.lines(path). Close it with try-with-resources.

Path path = Paths.get("employees.txt");

try (Stream<String> lines = Files.lines(path)) {
    lines.filter(line -> line.contains("IT"))
         .forEach(System.out::println);
}

Iterator / Iterable

Use StreamSupport.stream(...) when an object is iterable but not a collection.

Iterable<Employee> iterable = getEmployees();

Stream<Employee> stream = StreamSupport.stream(
    iterable.spliterator(),
    false
);

Generate / Iterate

Create streams without existing data using generate or iterate.

Stream.generate(Math::random)
    .limit(5)
    .forEach(System.out::println);

IntStream.iterate(1, n -> n + 1)
    .limit(10)
    .forEach(System.out::println);

Primitive Ranges

Use range streams when you need indexes or numbers.

IntStream.range(0, employees.size())
    .mapToObj(i -> (i + 1) + ". " + employees.get(i).getName())
    .forEach(System.out::println);