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)
| Method | Description |
|---|---|
filter(Predicate) | Keep elements matching predicate |
map(Function) | Transform each element |
mapToInt/Long/Double | Map to primitive stream |
flatMap(Function→Stream) | Flatten nested streams into one stream |
flatMapToInt/Long/Double | flatMap 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
| Method | Returns | Description |
|---|---|---|
forEach(Consumer) | void | Execute action for each element |
forEachOrdered(Consumer) | void | forEach preserving encounter order |
collect(Collector) | R | Accumulate 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) | T | Reduce to single value |
reduce(BinaryOp) | Optional<T> | Reduce without identity |
count() | long | Number 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) | boolean | At least one matches |
allMatch(Predicate) | boolean | All match |
noneMatch(Predicate) | boolean | None 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();