Java Cheatsheet

Streams

Use this Java reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

What Is a Stream

A Stream<T> is a lazy, single-use pipeline over a sequence of elements. It does not store data.

import java.util.stream.*;
import java.util.*;

Creating Streams

// From a collection
List<String> list = List.of("a","b","c");
Stream<String> s1 = list.stream();
Stream<String> s2 = list.parallelStream();   // parallel processing

// From values
Stream<String> s3 = Stream.of("x","y","z");
Stream<String> empty = Stream.empty();

// From an array
String[] arr = {"a","b","c"};
Stream<String> s4 = Arrays.stream(arr);
Stream<String> s5 = Arrays.stream(arr, 1, 3);  // [1,3) sub-range

// From a range (IntStream / LongStream)
IntStream  r1 = IntStream.range(0, 10);       // [0,10)
IntStream  r2 = IntStream.rangeClosed(1, 10); // [1,10]
LongStream r3 = LongStream.range(0L, 1_000_000L);

// Infinite / generated streams
Stream<Double> randoms = Stream.generate(Math::random);
Stream<Integer> evens  = Stream.iterate(0, n -> n + 2);
Stream<Integer> evensFinite = Stream.iterate(0, n -> n < 100, n -> n + 2); // Java 9+

// From String chars
IntStream chars = "hello".chars();

// From Builder
Stream.Builder<String> b = Stream.builder();
b.add("x"); b.add("y");
Stream<String> built = b.build();

Primitive Streams

IntStream    // for int
LongStream   // for long
DoubleStream // for double

// Conversion
IntStream intS = list.stream().mapToInt(String::length);
Stream<Integer> boxed = intS.boxed();              // IntStream → Stream<Integer>
IntStream asInt = stream.mapToInt(Integer::intValue);

// Primitive-specific terminal ops
IntStream s = IntStream.of(1,2,3,4,5);
s.sum()       // 15
s.average()   // OptionalDouble 3.0
s.min()       // OptionalInt 1
s.max()       // OptionalInt 5
s.count()     // 5
s.summaryStatistics() // IntSummaryStatistics{count=5, sum=15, min=1, avg=3.0, max=5}

Intermediate Operations (lazy, return Stream)

MethodDescription
filter(Predicate)Keep elements matching predicate
map(Function)Transform each element
mapToInt/Long/DoubleMap to primitive stream
flatMap(Function→Stream)Flatten nested streams into one stream
flatMapToInt/Long/DoubleflatMap to primitive stream
distinct()Remove duplicates (uses equals)
sorted()Natural order sort
sorted(Comparator)Custom order sort
limit(long n)Take at most n elements
skip(long n)Skip first n elements
peek(Consumer)Side-effect without consuming (debug)
takeWhile(Predicate) (J9+)Take while predicate is true, then stop
dropWhile(Predicate) (J9+)Drop while predicate is true, then yield rest
mapMulti(BiConsumer) (J16+)Flexible 1-to-many transformation
unordered()Hint: order doesn't matter (may improve parallel perf)
List<String> names = List.of("Alice","Bob","Charlie","Anna","Brian");

names.stream()
     .filter(n -> n.startsWith("A"))          // ["Alice","Anna"]
     .map(String::toUpperCase)                // ["ALICE","ANNA"]
     .sorted()                               // ["ALICE","ANNA"]
     .forEach(System.out::println);

// flatMap: stream of lists → single stream
List<List<Integer>> nested = List.of(List.of(1,2), List.of(3,4));
List<Integer> flat = nested.stream()
    .flatMap(Collection::stream)              // [1,2,3,4]
    .collect(Collectors.toList());

// distinct + limit
IntStream.of(1,2,2,3,1,4)
    .distinct()                               // 1,2,3,4
    .limit(3)                                 // 1,2,3
    .forEach(System.out::println);

Terminal Operations

MethodReturnsDescription
forEach(Consumer)voidExecute action for each element
forEachOrdered(Consumer)voidforEach preserving encounter order
collect(Collector)RAccumulate into collection or other result
toList() (J16+)List<T>Shorthand for collect(Collectors.toList())
toArray()Object[]Convert to array
toArray(IntFunction)T[]Convert to typed array
reduce(identity, BinaryOp)TReduce to single value
reduce(BinaryOp)Optional<T>Reduce without identity
count()longNumber of elements
min(Comparator)Optional<T>Minimum element
max(Comparator)Optional<T>Maximum element
findFirst()Optional<T>First element (empty if none)
findAny()Optional<T>Any element (non-deterministic in parallel)
anyMatch(Predicate)booleanAt least one matches
allMatch(Predicate)booleanAll match
noneMatch(Predicate)booleanNone match
List<Integer> nums = List.of(1,2,3,4,5,6,7,8,9,10);

long count  = nums.stream().filter(n -> n % 2 == 0).count();          // 5
int  sum    = nums.stream().reduce(0, Integer::sum);                   // 55
Optional<Integer> max = nums.stream().max(Comparator.naturalOrder()); // 10
boolean hasEven = nums.stream().anyMatch(n -> n % 2 == 0);            // true
boolean allPos  = nums.stream().allMatch(n -> n > 0);                 // true

// toArray
String[] arr = Stream.of("a","b","c").toArray(String[]::new);

Collectors

import java.util.stream.Collectors;

List<String> toList   = stream.collect(Collectors.toList());
Set<String>  toSet    = stream.collect(Collectors.toSet());
String joined         = stream.collect(Collectors.joining(", "));           // "a, b, c"
String joined2        = stream.collect(Collectors.joining(", ","[","]"));   // "[a, b, c]"

// toMap
Map<String,Integer> lenMap = words.stream()
    .collect(Collectors.toMap(
        w -> w,           // key
        String::length    // value
    ));

// merge function to handle duplicate keys
Map<String,Integer> freq = words.stream()
    .collect(Collectors.toMap(w -> w, w -> 1, Integer::sum));

// groupingBy
Map<Integer, List<String>> byLen = words.stream()
    .collect(Collectors.groupingBy(String::length));

// groupingBy + downstream collector
Map<Integer, Long> countByLen = words.stream()
    .collect(Collectors.groupingBy(String::length, Collectors.counting()));

Map<Integer, String> joinByLen = words.stream()
    .collect(Collectors.groupingBy(String::length, Collectors.joining(",")));

// partitioningBy (splits into true/false)
Map<Boolean, List<Integer>> parts = nums.stream()
    .collect(Collectors.partitioningBy(n -> n % 2 == 0));
// {true=[2,4,6,...], false=[1,3,5,...]}

// counting, summingInt, averagingInt
long count = stream.collect(Collectors.counting());
int  total = stream.collect(Collectors.summingInt(String::length));
double avg = stream.collect(Collectors.averagingInt(String::length));

// summarizingInt (all stats at once)
IntSummaryStatistics stats = stream.collect(Collectors.summarizingInt(String::length));
stats.getCount(); stats.getSum(); stats.getMin(); stats.getMax(); stats.getAverage();

// toUnmodifiableList / toUnmodifiableSet / toUnmodifiableMap (Java 10+)
List<String> immutable = stream.collect(Collectors.toUnmodifiableList());

// Collectors.teeing (Java 12+) — two collectors, combine results
var result = stream.collect(
    Collectors.teeing(
        Collectors.counting(),
        Collectors.summingInt(Integer::intValue),
        (count2, sum) -> "count=" + count2 + " sum=" + sum
    )
);

reduce

// With identity (always returns T)
int sum = IntStream.rangeClosed(1, 10).reduce(0, Integer::sum);  // 55

// Without identity (returns Optional — stream may be empty)
Optional<Integer> product = Stream.of(1,2,3,4,5)
    .reduce((a, b) -> a * b);    // Optional[120]

// Three-arg reduce (parallel-friendly; combiner merges partial results)
int sum2 = Stream.of("one","two","three")
    .reduce(0,
        (acc, s) -> acc + s.length(),   // accumulator
        Integer::sum);                  // combiner (for parallel)

Optional

Optional<String> opt = list.stream().filter(s -> s.startsWith("Z")).findFirst();

opt.isPresent()                     // true/false
opt.isEmpty()                       // Java 11+
opt.get()                           // value or NoSuchElementException
opt.orElse("default")              // value or "default"
opt.orElseGet(() -> compute())     // lazy alternative
opt.orElseThrow()                  // throws NoSuchElementException
opt.orElseThrow(MyEx::new)         // custom exception
opt.map(String::toUpperCase)       // Optional<String>
opt.flatMap(s -> findUser(s))      // Optional<User>
opt.filter(s -> s.length() > 3)    // Optional (same or empty)
opt.ifPresent(System.out::println) // action if present
opt.ifPresentOrElse(fn, emptyFn)  // Java 9+
opt.stream()                       // Java 9+: Stream of 0 or 1 elements
opt.or(() -> Optional.of("alt"))   // Java 9+: alternative Optional

Parallel Streams

long count = list.parallelStream()
    .filter(s -> s.length() > 3)
    .count();

// Convert sequential to parallel and back
stream.parallel()
stream.sequential()

// Use when:
// - Large data sets (overhead not worth it for small collections)
// - Independent, stateless, non-interfering operations
// - No shared mutable state
// Avoid when:
// - Order matters (use forEachOrdered if you need order)
// - Operations have side effects or shared state

Stream Concatenation and Flattening

Stream<String> combined = Stream.concat(stream1, stream2);

// Flatten list of streams
List<Stream<Integer>> streams = ...;
Stream<Integer> merged = streams.stream().flatMap(Function.identity());

Common Stream Patterns

// Counting words
Map<String, Long> wordCount = Arrays.stream(text.split("\\s+"))
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

// Top N items
List<String> top5 = words.stream()
    .sorted(Comparator.comparingInt(String::length).reversed())
    .limit(5)
    .collect(Collectors.toList());

// Deduplication preserving order
List<String> unique = list.stream()
    .distinct()
    .collect(Collectors.toList());

// Flat list of nested collections
List<String> allTags = users.stream()
    .flatMap(u -> u.getTags().stream())
    .distinct()
    .sorted()
    .collect(Collectors.toList());

// Partition students into pass/fail
Map<Boolean, List<Student>> result = students.stream()
    .collect(Collectors.partitioningBy(s -> s.getGrade() >= 60));

// Average of filtered values
OptionalDouble avg = nums.stream()
    .filter(n -> n > 0)
    .mapToInt(Integer::intValue)
    .average();