Overview
Streams in Java provide a powerful way to process sequences of elements. They can be created from various data sources including collections, arrays, I/O channels, and generator functions.
1. Streams from Collections
Basic Collection Streams
import java.util.*; import java.util.stream.*; public class CollectionStreams { public static void main(String[] args) { // List to Stream List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Diana"); Stream<String> nameStream = names.stream(); System.out.println("List stream count: " + nameStream.count()); // Set to Stream Set<Integer> numbers = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5)); Stream<Integer> numberStream = numbers.stream(); System.out.println("Set stream count: " + numberStream.count()); // Map to Stream Map<String, Integer> ageMap = new HashMap<>(); ageMap.put("Alice", 25); ageMap.put("Bob", 30); ageMap.put("Charlie", 35); // Stream of keys Stream<String> keyStream = ageMap.keySet().stream(); System.out.println("Keys: " + keyStream.collect(Collectors.toList())); // Stream of values Stream<Integer> valueStream = ageMap.values().stream(); System.out.println("Values: " + valueStream.collect(Collectors.toList())); // Stream of entries Stream<Map.Entry<String, Integer>> entryStream = ageMap.entrySet().stream(); entryStream.forEach(entry -> System.out.println(entry.getKey() + ": " + entry.getValue())); } } Parallel Streams from Collections
import java.util.*; import java.util.stream.*; public class ParallelStreams { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // Sequential stream long startTime = System.currentTimeMillis(); List<Integer> squares = numbers.stream() .map(n -> { try { Thread.sleep(100); } catch (Exception e) {} return n * n; }) .collect(Collectors.toList()); long sequentialTime = System.currentTimeMillis() - startTime; // Parallel stream startTime = System.currentTimeMillis(); List<Integer> squaresParallel = numbers.parallelStream() .map(n -> { try { Thread.sleep(100); } catch (Exception e) {} return n * n; }) .collect(Collectors.toList()); long parallelTime = System.currentTimeMillis() - startTime; System.out.println("Sequential time: " + sequentialTime + "ms"); System.out.println("Parallel time: " + parallelTime + "ms"); System.out.println("Results equal: " + squares.equals(squaresParallel)); } } 2. Streams from Arrays
Basic Array Streams
import java.util.*; import java.util.stream.*; public class ArrayStreams { public static void main(String[] args) { // Primitive array streams int[] intArray = {1, 2, 3, 4, 5}; IntStream intStream = Arrays.stream(intArray); System.out.println("Int stream sum: " + intStream.sum()); double[] doubleArray = {1.1, 2.2, 3.3, 4.4, 5.5}; DoubleStream doubleStream = Arrays.stream(doubleArray); System.out.println("Double stream average: " + doubleStream.average().orElse(0)); long[] longArray = {100L, 200L, 300L}; LongStream longStream = Arrays.stream(longArray); System.out.println("Long stream count: " + longStream.count()); // Object array streams String[] stringArray = {"Apple", "Banana", "Cherry"}; Stream<String> stringStream = Arrays.stream(stringArray); System.out.println("String stream: " + stringStream.collect(Collectors.toList())); // Stream with range String[] partialArray = {"A", "B", "C", "D", "E"}; Stream<String> partialStream = Arrays.stream(partialArray, 1, 4); // B, C, D System.out.println("Partial stream: " + partialStream.collect(Collectors.toList())); } } Multi-dimensional Array Streams
import java.util.*; import java.util.stream.*; public class MultiDimensionalArrayStreams { public static void main(String[] args) { // 2D array Integer[][] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; // Flatten 2D array to 1D stream Stream<Integer> flatStream = Arrays.stream(matrix) .flatMap(Arrays::stream); System.out.println("Flattened matrix: " + flatStream.collect(Collectors.toList())); // Process rows Stream<Integer[]> rowStream = Arrays.stream(matrix); rowStream.forEach(row -> System.out.println("Row: " + Arrays.toString(row))); // 3D array example Integer[][][] cube = { {{1, 2}, {3, 4}}, {{5, 6}, {7, 8}} }; // Flatten 3D array Stream<Integer> cubeStream = Arrays.stream(cube) .flatMap(Arrays::stream) .flatMap(Arrays::stream); System.out.println("Flattened cube: " + cubeStream.collect(Collectors.toList())); } } 3. Stream Factory Methods
Stream.of()
import java.util.*; import java.util.stream.*; public class StreamOfMethods { public static void main(String[] args) { // Stream.of() with individual elements Stream<String> singleElementStream = Stream.of("Hello"); System.out.println("Single element: " + singleElementStream.collect(Collectors.toList())); Stream<String> multipleElementsStream = Stream.of("Apple", "Banana", "Cherry"); System.out.println("Multiple elements: " + multipleElementsStream.collect(Collectors.toList())); // Stream.of() with array Stream<Integer> arrayStream = Stream.of(1, 2, 3, 4, 5); System.out.println("Array elements: " + arrayStream.collect(Collectors.toList())); // Stream of different types Stream<Object> mixedStream = Stream.of("String", 42, 3.14, true); mixedStream.forEach(obj -> System.out.println(obj + " (" + obj.getClass().getSimpleName() + ")")); // Empty stream Stream<String> emptyStream = Stream.of(); System.out.println("Empty stream count: " + emptyStream.count()); // Null handling Stream<String> withNull = Stream.of("A", null, "C"); withNull.forEach(element -> System.out.println("Element: " + element)); } } Stream.builder()
import java.util.*; import java.util.stream.*; public class StreamBuilderExample { public static void main(String[] args) { // Using Stream.builder() Stream.Builder<String> builder = Stream.builder(); builder.add("First") .add("Second") .add("Third") .add("Fourth"); Stream<String> builtStream = builder.build(); System.out.println("Built stream: " + builtStream.collect(Collectors.toList())); // Conditional building Stream.Builder<Integer> conditionalBuilder = Stream.builder(); for (int i = 1; i <= 10; i++) { if (i % 2 == 0) { // Only add even numbers conditionalBuilder.add(i); } } Stream<Integer> evenStream = conditionalBuilder.build(); System.out.println("Even numbers: " + evenStream.collect(Collectors.toList())); // Complex object building Stream.Builder<Person> personBuilder = Stream.builder(); personBuilder.add(new Person("Alice", 25)) .add(new Person("Bob", 30)) .add(new Person("Charlie", 35)); Stream<Person> personStream = personBuilder.build(); personStream.forEach(p -> System.out.println(p.name + " - " + p.age)); } static class Person { String name; int age; Person(String name, int age) { this.name = name; this.age = age; } } } 4. Specialized Streams
IntStream, LongStream, DoubleStream
import java.util.*; import java.util.stream.*; public class SpecializedStreams { public static void main(String[] args) { // IntStream examples System.out.println("=== IntStream ==="); IntStream.range(1, 6).forEach(System.out::println); // 1,2,3,4,5 IntStream.rangeClosed(1, 5).forEach(System.out::println); // 1,2,3,4,5 int sum = IntStream.of(1, 2, 3, 4, 5).sum(); System.out.println("Sum: " + sum); OptionalDouble average = IntStream.range(1, 11).average(); System.out.println("Average: " + average.orElse(0)); // LongStream examples System.out.println("\n=== LongStream ==="); LongStream.range(100L, 105L).forEach(System.out::println); long product = LongStream.rangeClosed(1L, 5L) .reduce(1, (a, b) -> a * b); System.out.println("Product: " + product); // DoubleStream examples System.out.println("\n=== DoubleStream ==="); DoubleStream.of(1.1, 2.2, 3.3, 4.4, 5.5) .forEach(d -> System.out.printf("%.1f ", d)); System.out.println(); double[] doubles = DoubleStream.generate(Math::random) .limit(5) .toArray(); System.out.println("Random doubles: " + Arrays.toString(doubles)); // Converting between stream types System.out.println("\n=== Conversions ==="); IntStream intStream = IntStream.range(1, 6); Stream<Integer> boxedStream = intStream.boxed(); System.out.println("Boxed stream: " + boxedStream.collect(Collectors.toList())); Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5); IntStream unboxedStream = integerStream.mapToInt(Integer::intValue); System.out.println("Sum of unboxed: " + unboxedStream.sum()); } } 5. Infinite Streams
Stream.generate()
import java.util.*; import java.util.stream.*; import java.util.concurrent.atomic.*; public class GenerateStreams { public static void main(String[] args) { // Generate random numbers System.out.println("=== Random Numbers ==="); Stream<Double> randomStream = Stream.generate(Math::random) .limit(5); randomStream.forEach(System.out::println); // Generate constant values System.out.println("\n=== Constant Values ==="); Stream<String> constantStream = Stream.generate(() -> "Hello") .limit(3); constantStream.forEach(System.out::println); // Generate with state (using AtomicInteger) System.out.println("\n=== Stateful Generation ==="); AtomicInteger counter = new AtomicInteger(1); Stream<Integer> statefulStream = Stream.generate(() -> counter.getAndIncrement()) .limit(5); statefulStream.forEach(System.out::println); // Generate Fibonacci sequence System.out.println("\n=== Fibonacci Sequence ==="); long[] fib = {0, 1}; Stream<Long> fibonacciStream = Stream.generate(() -> { long next = fib[0] + fib[1]; long result = fib[0]; fib[0] = fib[1]; fib[1] = next; return result; }).limit(10); fibonacciStream.forEach(n -> System.out.print(n + " ")); System.out.println(); // Generate UUIDs System.out.println("\n=== UUIDs ==="); Stream<String> uuidStream = Stream.generate(() -> UUID.randomUUID().toString()) .limit(3); uuidStream.forEach(System.out::println); } } Stream.iterate()
import java.util.*; import java.util.stream.*; public class IterateStreams { public static void main(String[] args) { // Basic iterate - arithmetic sequence System.out.println("=== Arithmetic Sequence ==="); Stream<Integer> arithmetic = Stream.iterate(0, n -> n + 2) .limit(5); arithmetic.forEach(n -> System.out.print(n + " ")); // 0, 2, 4, 6, 8 System.out.println(); // Geometric sequence System.out.println("\n=== Geometric Sequence ==="); Stream<Integer> geometric = Stream.iterate(1, n -> n * 2) .limit(6); geometric.forEach(n -> System.out.print(n + " ")); // 1, 2, 4, 8, 16, 32 System.out.println(); // Fibonacci with iterate System.out.println("\n=== Fibonacci with Iterate ==="); Stream.iterate(new long[]{0, 1}, fib -> new long[]{fib[1], fib[0] + fib[1]}) .limit(10) .map(fib -> fib[0]) .forEach(n -> System.out.print(n + " ")); System.out.println(); // Conditional iteration with predicate (Java 9+) System.out.println("\n=== Conditional Iteration ==="); Stream<Integer> limited = Stream.iterate(1, n -> n <= 32, n -> n * 2); limited.forEach(n -> System.out.print(n + " ")); // 1, 2, 4, 8, 16, 32 System.out.println(); // String sequence System.out.println("\n=== String Sequence ==="); Stream.iterate("A", s -> s + s.charAt(0)) .limit(5) .forEach(System.out::println); } } 6. Streams from I/O Operations
Files.lines()
import java.io.*; import java.nio.file.*; import java.util.*; import java.util.stream.*; public class FileStreams { public static void main(String[] args) { try { // Create a sample file Path tempFile = Files.createTempFile("sample", ".txt"); List<String> lines = Arrays.asList( "Line 1: Hello World", "Line 2: Java Streams", "Line 3: File Processing", "Line 4: Lambda Expressions", "Line 5: Functional Programming" ); Files.write(tempFile, lines); // Read file as stream System.out.println("=== Reading File as Stream ==="); try (Stream<String> fileStream = Files.lines(tempFile)) { fileStream.forEach(System.out::println); } // Process file content System.out.println("\n=== Processing File Content ==="); try (Stream<String> processedStream = Files.lines(tempFile)) { long lineCount = processedStream .filter(line -> line.contains("Java")) .count(); System.out.println("Lines containing 'Java': " + lineCount); } // Read and transform System.out.println("\n=== Transforming File Content ==="); try (Stream<String> transformStream = Files.lines(tempFile)) { List<String> uppercaseLines = transformStream .map(String::toUpperCase) .collect(Collectors.toList()); uppercaseLines.forEach(System.out::println); } // Clean up Files.deleteIfExists(tempFile); } catch (IOException e) { e.printStackTrace(); } // Reading from classpath resource System.out.println("\n=== Reading from Classpath ==="); try (InputStream is = FileStreams.class.getResourceAsStream("/data.txt"); BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { Stream<String> classpathStream = reader.lines(); classpathStream.limit(3).forEach(System.out::println); } catch (Exception e) { System.out.println("Resource not found: " + e.getMessage()); } } } BufferedReader.lines()
import java.io.*; import java.util.*; import java.util.stream.*; public class BufferedReaderStreams { public static void main(String[] args) { String text = "First Line\nSecond Line\nThird Line\nFourth Line\nFifth Line"; // Using BufferedReader with StringReader try (StringReader stringReader = new StringReader(text); BufferedReader bufferedReader = new BufferedReader(stringReader)) { Stream<String> linesStream = bufferedReader.lines(); System.out.println("=== All Lines ==="); linesStream.forEach(System.out::println); } catch (IOException e) { e.printStackTrace(); } // Processing with filters try (StringReader stringReader = new StringReader(text); BufferedReader bufferedReader = new BufferedReader(stringReader)) { System.out.println("\n=== Lines containing 'Second' ==="); bufferedReader.lines() .filter(line -> line.contains("Second")) .forEach(System.out::println); } catch (IOException e) { e.printStackTrace(); } } } 7. Stream Concatenation
Stream.concat()
import java.util.*; import java.util.stream.*; public class StreamConcatenation { public static void main(String[] args) { // Concatenating two streams Stream<String> stream1 = Stream.of("A", "B", "C"); Stream<String> stream2 = Stream.of("D", "E", "F"); Stream<String> concatenated = Stream.concat(stream1, stream2); System.out.println("Concatenated: " + concatenated.collect(Collectors.toList())); // Concatenating multiple streams Stream<Integer> numbers1 = Stream.of(1, 2, 3); Stream<Integer> numbers2 = Stream.of(4, 5, 6); Stream<Integer> numbers3 = Stream.of(7, 8, 9); Stream<Integer> allNumbers = Stream.concat( Stream.concat(numbers1, numbers2), numbers3 ); System.out.println("All numbers: " + allNumbers.collect(Collectors.toList())); // Concatenating with different types (using map) Stream<String> stringStream = Stream.of("1", "2", "3"); Stream<Integer> intStream = Stream.of(4, 5, 6); Stream<Integer> mixedConcatenated = Stream.concat( stringStream.map(Integer::parseInt), intStream ); System.out.println("Mixed concatenated: " + mixedConcatenated.collect(Collectors.toList())); // Practical example - merging data from different sources List<String> databaseResults = Arrays.asList("DB1", "DB2", "DB3"); List<String> apiResults = Arrays.asList("API1", "API2"); List<String> fileResults = Arrays.asList("FILE1", "FILE2", "FILE3"); Stream<String> combinedResults = Stream.concat( databaseResults.stream(), Stream.concat(apiResults.stream(), fileResults.stream()) ); System.out.println("Combined results: " + combinedResults.collect(Collectors.toList())); } } 8. Pattern and String Streams
Pattern.splitAsStream()
import java.util.*; import java.util.regex.*; import java.util.stream.*; public class PatternStreams { public static void main(String[] args) { String text = "Apple,Banana,Cherry,Date,Fig,Grape"; // Split string using pattern Pattern pattern = Pattern.compile(","); Stream<String> fruitStream = pattern.splitAsStream(text); System.out.println("Fruits: " + fruitStream.collect(Collectors.toList())); // Complex pattern matching String logData = "ERROR: Database connection failed\n" + "INFO: User logged in\n" + "WARN: High memory usage\n" + "ERROR: File not found\n" + "DEBUG: Processing request"; Pattern errorPattern = Pattern.compile("ERROR:.*", Pattern.MULTILINE); Stream<String> errorStream = errorPattern.splitAsStream(logData); System.out.println("\nError messages:"); errorStream.filter(s -> !s.isEmpty()) .forEach(System.out::println); // Extract specific patterns String data = "John:25, Alice:30, Bob:35, Charlie:40"; Pattern agePattern = Pattern.compile("(\\w+):(\\d+)"); Stream<String> ageStream = agePattern.splitAsStream(data); ageStream.filter(s -> !s.isEmpty() && s.contains(",")) .map(s -> s.replace(",", "").trim()) .forEach(System.out::println); // Using Matcher with stream (alternative approach) System.out.println("\nUsing Matcher:"); Matcher matcher = agePattern.matcher(data); matcher.results() .forEach(matchResult -> System.out.println(matchResult.group(1) + " is " + matchResult.group(2))); } } String.chars() and String.codePoints()
import java.util.*; import java.util.stream.*; public class StringCharacterStreams { public static void main(String[] args) { String text = "Hello Java 8 Streams!"; // String.chars() - returns IntStream of char values System.out.println("=== String.chars() ==="); text.chars() .forEach(ch -> System.out.print((char) ch + " ")); System.out.println(); // Count vowels using chars() long vowelCount = text.chars() .filter(Character::isLetter) .map(Character::toLowerCase) .filter(ch -> "aeiou".indexOf(ch) != -1) .count(); System.out.println("Vowel count: " + vowelCount); // String.codePoints() - handles Unicode characters properly System.out.println("\n=== String.codePoints() ==="); String unicodeText = "Hello 🚀 World 🌍"; unicodeText.codePoints() .forEach(cp -> System.out.print(Character.toChars(cp))); System.out.println(); // Count code points vs chars System.out.println("Length by chars(): " + unicodeText.chars().count()); System.out.println("Length by codePoints(): " + unicodeText.codePoints().count()); System.out.println("String length: " + unicodeText.length()); // Convert to Character stream System.out.println("\n=== Character Stream ==="); Stream<Character> charStream = text.chars() .mapToObj(ch -> (char) ch); charStream.forEach(ch -> System.out.print(ch + " ")); System.out.println(); } } 9. Empty and Single Element Streams
Stream.empty()
import java.util.*; import java.util.stream.*; public class EmptyStreams { public static void main(String[] args) { // Empty stream Stream<String> emptyStream = Stream.empty(); System.out.println("Empty stream count: " + emptyStream.count()); // Using empty stream as default List<String> maybeEmptyList = Collections.emptyList(); Stream<String> safeStream = maybeEmptyList != null ? maybeEmptyList.stream() : Stream.empty(); System.out.println("Safe stream count: " + safeStream.count()); // Combining with other streams Stream<String> hasData = Stream.of("A", "B", "C"); Stream<String> noData = Stream.empty(); Stream<String> combined = Stream.concat(hasData, noData); System.out.println("Combined with empty: " + combined.collect(Collectors.toList())); // Using in method returns System.out.println("Search results: " + searchData("valid").collect(Collectors.toList())); System.out.println("Search results: " + searchData("invalid").collect(Collectors.toList())); // Empty specialized streams IntStream emptyIntStream = IntStream.empty(); LongStream emptyLongStream = LongStream.empty(); DoubleStream emptyDoubleStream = DoubleStream.empty(); System.out.println("Empty IntStream sum: " + emptyIntStream.sum()); System.out.println("Empty LongStream count: " + emptyLongStream.count()); System.out.println("Empty DoubleStream average: " + emptyDoubleStream.average().orElse(0.0)); } public static Stream<String> searchData(String query) { if ("valid".equals(query)) { return Stream.of("Result1", "Result2", "Result3"); } else { return Stream.empty(); // Better than returning null } } } 10. Advanced Stream Creation Patterns
Custom Stream Sources
import java.util.*; import java.util.stream.*; public class CustomStreamSources { // Custom iterator-based stream public static Stream<Integer> fibonacciStream(int limit) { return Stream.iterate(new int[]{0, 1}, fib -> new int[]{fib[1], fib[0] + fib[1]}) .limit(limit) .map(fib -> fib[0]); } // Custom generator with state public static Stream<String> numberedStream(String prefix, int count) { AtomicInteger counter = new AtomicInteger(1); return Stream.generate(() -> prefix + counter.getAndIncrement()) .limit(count); } // Stream from custom data structure static class TreeNode { String value; List<TreeNode> children; TreeNode(String value, TreeNode... children) { this.value = value; this.children = Arrays.asList(children); } // Depth-first traversal stream Stream<TreeNode> depthFirst() { return Stream.concat( Stream.of(this), children.stream().flatMap(TreeNode::depthFirst) ); } // Breadth-first traversal stream Stream<TreeNode> breadthFirst() { return Stream.iterate( Collections.singletonList(this), list -> list.stream() .flatMap(node -> node.children.stream()) .collect(Collectors.toList()) ) .takeWhile(list -> !list.isEmpty()) .flatMap(List::stream); } } public static void main(String[] args) { System.out.println("=== Custom Fibonacci ==="); fibonacciStream(10).forEach(n -> System.out.print(n + " ")); System.out.println(); System.out.println("\n=== Numbered Stream ==="); numberedStream("Item-", 5).forEach(System.out::println); System.out.println("\n=== Tree Traversal ==="); TreeNode root = new TreeNode("A", new TreeNode("B", new TreeNode("D"), new TreeNode("E")), new TreeNode("C", new TreeNode("F"), new TreeNode("G")) ); System.out.println("Depth-first:"); root.depthFirst().map(node -> node.value).forEach(v -> System.out.print(v + " ")); System.out.println("\nBreadth-first:"); root.breadthFirst().map(node -> node.value).forEach(v -> System.out.print(v + " ")); System.out.println(); } } Best Practices Summary
import java.util.*; import java.util.stream.*; public class StreamCreationBestPractices { public static void main(String[] args) { // 1. Prefer collection streams for existing data List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); Stream<String> goodStream = names.stream(); // Good Stream<String> verboseStream = Stream.of("Alice", "Bob", "Charlie"); // Less ideal // 2. Use appropriate stream type for primitives int[] numbers = {1, 2, 3, 4, 5}; IntStream efficient = Arrays.stream(numbers); // Good - no boxing Stream<Integer> inefficient = Stream.of(1, 2, 3, 4, 5); // Boxing overhead // 3. Close I/O-based streams try (Stream<String> fileStream = Files.lines(Paths.get("data.txt"))) { fileStream.forEach(System.out::println); } catch (IOException e) { e.printStackTrace(); } // 4. Use empty() instead of null public Stream<String> getData() { return dataAvailable ? data.stream() : Stream.empty(); // Good // return dataAvailable ? data.stream() : null; // Bad } // 5. Consider parallel streams for CPU-intensive operations List<Integer> largeList = // ... large collection largeList.parallelStream() // Good for CPU-bound tasks .map(x -> expensiveOperation(x)) .collect(Collectors.toList()); // 6. Use builder for complex stream construction Stream.Builder<String> builder = Stream.builder(); if (condition1) builder.add("A"); if (condition2) builder.add("B"); if (condition3) builder.add("C"); Stream<String> complexStream = builder.build(); // 7. Prefer method references in stream pipelines names.stream().map(String::toUpperCase); // Good names.stream().map(s -> s.toUpperCase()); // Okay, but verbose } } Key Points Summary
- Collection Streams:
collection.stream(),collection.parallelStream() - Array Streams:
Arrays.stream(),Stream.of() - Factory Methods:
Stream.generate(),Stream.iterate(),Stream.builder() - I/O Streams:
Files.lines(),BufferedReader.lines() - Specialized Streams:
IntStream,LongStream,DoubleStream - String Streams:
String.chars(),String.codePoints(),Pattern.splitAsStream() - Empty Streams:
Stream.empty()for safe API design - Concatenation:
Stream.concat()for combining streams
Stream creation is the foundation of stream processing in Java, and understanding these various creation methods enables you to work with data from diverse sources efficiently.