Java 8 introduces a fresh package known as java.util.stream, offering a variety of classes, interfaces, and enums for performing functional-style actions on elements. To leverage streams, the java.util.stream package needs to be imported.
Stream provides following features:
- Stream does not store elements. It simply conveys elements from a source such as a data structure, an array, or an I/O channel, through a pipeline of computational operations.
- Stream is functional in nature. Operations performed on a stream does not modify it's source. For example, filtering a Stream obtained from a collection produces a new Stream without the filtered elements, rather than removing elements from the source collection.
- Stream is lazy and evaluates code only when required.
- The elements of a stream are only visited once during the life of a stream. Like an Iterator, a new stream must be generated to revisit the same elements of the source.
Streams in Java can be utilized for operations like filtering, collecting, printing, and transforming data structures. Below are instances demonstrating the application of different operations using streams.
Various Core Operations Over Streams
1. Intermediate Operations
In Java Streams, intermediate operations produce a new Stream and are commonly employed to modify or sift through the elements of the initial Stream. These operations are deferred, indicating that they do not execute any actions until a terminal operation is invoked, allowing for the chaining of multiple intermediate operations.
Common Intermediate Operations:
- map(Function<T, R>): Transforms each element of the Stream into another form using the provided function.
- filter(Predicate<T>): Selects elements from the Stream based on a specified condition.
- flatMap(Function<T, Stream<R>>): Transforms each element into zero or more elements by applying a function that returns a stream for each element.
- distinct: Removes duplicate elements from the Stream.
- sorted: Sorts the elements of the Stream.
- limit(long n): Truncates the Stream to be no longer than the specified size.
- skip(long n): Skips the first n elements of the Stream.
- peek(Consumer<T>): Performs a specified action on each element of the Stream without consuming the elements.
2. Terminal Operations
Operations that are considered terminal in streams are the ones that utilize the stream and generate an outcome, which could be a value, a set of data, or an action. When a terminal operation is executed, the stream is handled entirely and becomes ineligible for further use.
Common Terminal Operations:
- forEach(Consumer<T>): Acts as each element of the Stream.
- collect(Collector<T, A, R>): Reduces the elements of the Stream into a mutable result container, such as a list or a map.
- reduce(BinaryOperator<T>): Reduces the elements of the Stream to a single value using an associative accumulation function.
- count: Returns the count of elements in the Stream.
- anyMatch(Predicate<T>): Returns true if any element of the Stream matches the given predicate.
- allMatch(Predicate<T>): Returns true if all elements of the Stream match the given predicate.
- noneMatch(Predicate<T>): Returns true if no elements of the Stream match the given predicate.
- findFirst: Returns an Optional describing the first element of the Stream, or an empty Optional if the Stream is empty.
- findAny: Returns an Optional describing some element of the Stream, or an empty Optional if the Stream is empty.
3. Short-Circuit Operations
Short-circuit operations represent a category of terminal operations that do not require processing the complete Stream in order to generate an output. These operations enable an early termination from the stream processing sequence, which can lead to saved computational resources and time.
Common Short-Circuit Operations:
- anyMatch(Predicate<T>): Stops processing and returns true if any element matches the given predicate.
- allMatch(Predicate<T>): Stops processing and returns false if any element does not match the given predicate.
- noneMatch(Predicate<T>): Stops processing and returns true if no elements match the given predicate.
- findFirst: Returns the first element encountered in the Stream and then stops processing.
- findAny: Returns any element encountered in the Stream and then stops processing.
Java Stream Interface Methods
| Methods | Description | |||
|---|---|---|---|---|
| boolean allMatch(Predicate<? super T> predicate) | It returns all elements of this stream which match the provided predicate. If the stream is empty then true is returned and the predicate is not evaluated. | |||
| boolean anyMatch(Predicate<? super T> predicate) | It returns any element of this stream that matches the provided predicate. If the stream is empty then false is returned and the predicate is not evaluated. | |||
| static static <T> Stream.Builder<T> builder() Stream.BuilderStream builder() | It returns a builder for a Stream. | |||
| <R> R collect(Collector<Collector> collector) | It performs a mutable reduction operation on the elements of this stream using a Collector. A Collector encapsulates the functions used as arguments to collect(Supplier, BiConsumer, BiConsumer), allowing for reuse of collection strategies and composition of collect operations such as multiple-level grouping or partitioning. | |||
| <a> R collect(Supplier<Supplier<R>> supplier, BiConsumerBiConsumer<T, A> accumulator, BiConsumerBiConsumer<T, T> combiner) | It performs a mutable reduction operation on the elements of this stream. A mutable reduction is one in which the reduced value is a mutable result container, such as an ArrayList, and elements are incorporated by updating the state of the result rather than by replacing the result. | |||
| static static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) StreamStream concat(StreamStream<T> a, StreamStream<T> b) | It creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream. The resulting stream is ordered if both of the input streams are ordered, and parallel if either of the input streams is parallel. When the resulting stream is closed, the close handlers for both input streams are invoked. | |||
| long count() | It returns the count of elements in this stream. This is a special case of a reduction. | |||
| Stream<T> distinct() | It returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream. | |||
| static static <T> Stream<T> empty() StreamStream<T> empty() | It returns an empty sequential Stream. | |||
| StreamStream<T> filter(Predicate<? super T> predicate) filter(PredicatePredicate<T> predicate) | It returns a stream consisting of the elements of this stream that match the given predicate. | |||
| Optional<T> findAny() | It returns an Optional describing some element of the stream, or an empty Optional if the stream is empty. | |||
| Optional<T> findFirst() | It returns an Optional describing the first element of this stream, or an empty Optional if the stream is empty. If the stream has no encounter order, then any element may be returned. | |||
|
Stream<T> flatMap(Function<? super T,? extends Stream<? extends R>> mapper) | It returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function StreamStream<T> flatMap(FunctionFunction<? super T,? extends Stream<? extends R>>> mapper) | It returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. Each mapped stream is closed after its contents have been placed into this stream. (If a mapped stream is null an empty stream is used, instead.) | |
| DoubleStream flatMapToDouble(Function<? super T,? extends DoubleStream> mapper) | It returns a DoubleStream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. Each mapped stream is closed after its contents have placed been into this stream. (If a mapped stream is null an empty stream is used, instead.) | |||
| IntStream flatMapToInt(Function<? super T,? extends IntStream> mapper) | It returns an IntStream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. Each mapped stream is closed after its contents have been placed into this stream. (If a mapped stream is null an empty stream is used, instead.) | |||
| LongStream flatMapToLong(Function<? super T,? extends LongStream> mapper) | It returns a LongStream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. Each mapped stream is closed after its contents have been placed into this stream. (If a mapped stream is null an empty stream is used, instead.) | |||
| void forEach(Consumer<? super T> action) | It performs an action for each element of this stream. | |||
| void forEachOrdered(Consumer<? super T> action) | It performs an action for each element of this stream, in the encounter order of the stream if the stream has a defined encounter order. | |||
| static static <T> Stream<T> generate(Supplier<T> s) StreamStream generate(SupplierSupplier s) | It returns an infinite sequential unordered stream where each element is generated by the provided Supplier. This is suitable for generating constant streams, streams of random elements, etc. | |||
| static static <T> Stream<T> iterate(T seed, UnaryOperator<T> f) StreamStream<T> iterate(T seed,UnaryOperatorUnaryOperator<T> f) | It returns an infinite sequential ordered Stream produced by iterative application of a function f to an initial element seed, producing a Stream consisting of seed, f(seed), f(f(seed)), etc. | |||
| Stream<T> limit(long maxSize) | It returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length. | |||
| <a> Stream<Stream<T>> map(FunctionFunction<? super T> mapper) | It returns a stream consisting of the results of applying the given function to the elements of this stream. | |||
| DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) | It returns a DoubleStream consisting of the results of applying the given function to the elements of this stream. | |||
| IntStream mapToInt(ToIntFunction<? super T> mapper) | It returns an IntStream consisting of the results of applying the given function to the elements of this stream. | |||
| LongStream mapToLong(ToLongFunction<? super T> mapper) | It returns a LongStream consisting of the results of applying the given function to the elements of this stream. | |||
| OptionalOptional <T> max(Comparator<? super T> comparator) max(ComparatorComparator comparator) | It returns the maximum element of this stream according to the provided Comparator. This is a special case of a reduction. | |||
| OptionalOptional <T> min(Comparator<? super T> comparator) min(ComparatorComparator<? super T> comparator) | It returns the minimum element of this stream according to the provided Comparator. This is a special case of a reduction. | |||
| boolean noneMatch(Predicate<? super T> predicate) | It returns elements of this stream match the provided predicate. If the stream is empty then true is returned and the predicate is not evaluated. | |||
| @SafeVarargs static Stream<T> StreamStream of(T... values) | It returns a sequential ordered stream whose elements are the specified values. | |||
| static static <T> Stream<T> of(T t) StreamStream<T> of(T t) | It returns a sequential Stream containing a single element. | |||
| StreamStream<T> peek(Consumer<? super T> action) peek(Consumer<Consumer<T>> action) | It returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream. | |||
| OptionalOptional<T> reduce(BinaryOperator<T> accumulator) reduce(BinaryOperatorBinaryOperator<T> accumulator) | It performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any. | |||
| T reduce(T identity, BinaryOperator<T> accumulator) | It performs a reduction on the elements of this stream, using the provided identity value and an associative accumulation function, and returns the reduced value. | |||
| <U> U reduce(U identity, BiFunctionBiFunction<T, U, T> accumulator, BinaryOperatorBinaryOperator<T> combiner) | It performs a reduction on the elements of this stream, using the provided identity, accumulation and combining functions. | |||
| Stream<T> skip(long n) | It returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream. If this stream contains fewer than n elements then an empty stream will be returned. | |||
| Stream<T> sorted() | It returns a stream consisting of the elements of this stream, sorted according to natural order. If the elements of this stream are not Comparable, a java.lang.ClassCastException may be thrown when the terminal operation is executed. | |||
| Stream | Stream<T> sorted(Comparator<T> comparator) | It returns a stream consisting of the elements of this stream, sorted according to the provided Comparator. | sorted(ComparatorComparator comparator) | It returns a stream consisting of the elements of this stream, sorted according to the provided Comparator. |
| Object[] toArray() | It returns an array containing the elements of this stream. | |||
|
<T> toArray(IntFunction<T[]> generator) | It returns an array containing the elements of this stream, using the provided generator function to allocate the returned array, as well as any additional arrays that might be required for a partitioned execution A[] toArray(IntFunction< T[] > generator) | It returns an array containing the elements of this stream, using the provided generator function to allocate the returned array, as well as any additional arrays that might be required for a partitioned execution or for resizing. |
Java Example: Filtering Collection without using Stream
In this instance, we will demonstrate data filtering without utilizing streams. This methodology was employed prior to the introduction of the stream package.
Example
import java.util.*;
class Product{
int id;
String name;
float price;
public Product(int id, String name, float price) {
this.id = id;
this.name = name;
this.price = price;
}
}
public class JavaStreamExample {
public static void main(String[] args) {
List<Product> productsList = new ArrayList<Product>();
//Adding Products
productsList.add(new Product(1,"HP Laptop",25000f));
productsList.add(new Product(2,"Dell Laptop",30000f));
productsList.add(new Product(3,"Lenevo Laptop",28000f));
productsList.add(new Product(4,"Sony Laptop",28000f));
productsList.add(new Product(5,"Apple Laptop",90000f));
List<Float> productPriceList = new ArrayList<Float>();
for(Product product: productsList){
// filtering data of list
if(product.price<30000){
productPriceList.add(product.price); // adding price to a productPriceList
}
}
System.out.println(productPriceList); // displaying data
}
}
Output:
[25000.0, 28000.0, 28000.0]
Java Stream Example: Filtering Collection by Using Stream
In this scenario, data filtration is being performed utilizing streams, leading to optimized and well-managed code. Streams offer rapid execution capabilities.
Example
import java.util.*;
import java.util.stream.Collectors;
class Product{
int id;
String name;
float price;
public Product(int id, String name, float price) {
this.id = id;
this.name = name;
this.price = price;
}
}
public class JavaStreamExample {
public static void main(String[] args) {
List<Product> productsList = new ArrayList<Product>();
//Adding Products
productsList.add(new Product(1,"HP Laptop",25000f));
productsList.add(new Product(2,"Dell Laptop",30000f));
productsList.add(new Product(3,"Lenevo Laptop",28000f));
productsList.add(new Product(4,"Sony Laptop",28000f));
productsList.add(new Product(5,"Apple Laptop",90000f));
List<Float> productPriceList2 =productsList.stream()
.filter(p -> p.price > 30000)// filtering data
.map(p->p.price) // fetching price
.collect(Collectors.toList()); // collecting as list
System.out.println(productPriceList2);
}
}
Output:
[90000.0]
Java Stream Iterating Example
Streams can be utilized for iterating multiple times. They offer built-in functions to handle the operations we specify. In the upcoming demonstration, we will iterate, apply a filter, and set a maximum limit for the iteration.
Example
import java.util.stream.*;
public class JavaStreamExample {
public static void main(String[] args){
Stream.iterate(1, element->element+1)
.filter(element->element%5==0)
.limit(5)
.forEach(System.out::println);
}
}
Output:
5
10
15
20
25
Java Stream Example: Filtering and Iterating Collection
In this instance, we are utilizing the filter function. It is evident that the code has been streamlined for better efficiency and brevity.
Example
import java.util.*;
class Product{
int id;
String name;
float price;
public Product(int id, String name, float price) {
this.id = id;
this.name = name;
this.price = price;
}
}
public class JavaStreamExample {
public static void main(String[] args) {
List<Product> productsList = new ArrayList<Product>();
//Adding Products
productsList.add(new Product(1,"HP Laptop",25000f));
productsList.add(new Product(2,"Dell Laptop",30000f));
productsList.add(new Product(3,"Lenevo Laptop",28000f));
productsList.add(new Product(4,"Sony Laptop",28000f));
productsList.add(new Product(5,"Apple Laptop",90000f));
// This is more compact approach for filtering data
productsList.stream()
.filter(product -> product.price == 30000)
.forEach(product -> System.out.println(product.name));
}
}
Output:
Dell Laptop
Java Stream Example : reduce Method in Collection
The process involves taking a series of input items and merging them into one concise outcome through iterative actions. For instance, calculating the total of numerical values or gathering elements into a collection.
In this instance, we demonstrate the utilization of the reduce function, employed to calculate the total sum of all product prices.
Example
import java.util.*;
class Product{
int id;
String name;
float price;
public Product(int id, String name, float price) {
this.id = id;
this.name = name;
this.price = price;
}
}
public class JavaStreamExample {
public static void main(String[] args) {
List<Product> productsList = new ArrayList<Product>();
//Adding Products
productsList.add(new Product(1,"HP Laptop",25000f));
productsList.add(new Product(2,"Dell Laptop",30000f));
productsList.add(new Product(3,"Lenevo Laptop",28000f));
productsList.add(new Product(4,"Sony Laptop",28000f));
productsList.add(new Product(5,"Apple Laptop",90000f));
// This is more compact approach for filtering data
Float totalPrice = productsList.stream()
.map(product->product.price)
.reduce(0.0f,(sum, price)->sum+price); // accumulating price
System.out.println(totalPrice);
// More precise code
float totalPrice2 = productsList.stream()
.map(product->product.price)
.reduce(0.0f,Float::sum); // accumulating price, by referring method of Float class
System.out.println(totalPrice2);
}
}
Output:
201000.0
201000.0
Java Stream Example: Sum by Using Collectors Methods
Another approach to calculate the total of numerical values is by utilizing collectors. In this instance, we are employing the Collectors class along with its designated techniques to determine the sum of all the prices of products.
Example
import java.util.*;
import java.util.stream.Collectors;
class Product{
int id;
String name;
float price;
public Product(int id, String name, float price) {
this.id = id;
this.name = name;
this.price = price;
}
}
public class JavaStreamExample {
public static void main(String[] args) {
List<Product> productsList = new ArrayList<Product>();
//Adding Products
productsList.add(new Product(1,"HP Laptop",25000f));
productsList.add(new Product(2,"Dell Laptop",30000f));
productsList.add(new Product(3,"Lenevo Laptop",28000f));
productsList.add(new Product(4,"Sony Laptop",28000f));
productsList.add(new Product(5,"Apple Laptop",90000f));
// Using Collectors's method to sum the prices.
double totalPrice3 = productsList.stream()
.collect(Collectors.summingDouble(product->product.price));
System.out.println(totalPrice3);
}
}
Output:
201000.0
Java Stream Example: Find Max and Min Product Price
The following example demonstrates how to find the minimum and maximum product prices using a stream. This technique offers a more streamlined method for obtaining these values, eliminating the need for an imperative approach.
Example
import java.util.*;
class Product{
int id;
String name;
float price;
public Product(int id, String name, float price) {
this.id = id;
this.name = name;
this.price = price;
}
}
public class JavaStreamExample {
public static void main(String[] args) {
List<Product> productsList = new ArrayList<Product>();
//Adding Products
productsList.add(new Product(1,"HP Laptop",25000f));
productsList.add(new Product(2,"Dell Laptop",30000f));
productsList.add(new Product(3,"Lenevo Laptop",28000f));
productsList.add(new Product(4,"Sony Laptop",28000f));
productsList.add(new Product(5,"Apple Laptop",90000f));
// max() method to get max Product price
Product productA = productsList.stream().max((product1, product2)->product1.price > product2.price ? 1: -1).get();
System.out.println(productA.price);
// min() method to get min Product price
Product productB = productsList.stream().min((product1, product2)->product1.price > product2.price ? 1: -1).get();
System.out.println(productB.price);
}
}
Output:
90000.0
25000.0
Java Stream Example: count Method in Collection
Example
import java.util.*;
class Product{
int id;
String name;
float price;
public Product(int id, String name, float price) {
this.id = id;
this.name = name;
this.price = price;
}
}
public class JavaStreamExample {
public static void main(String[] args) {
List<Product> productsList = new ArrayList<Product>();
//Adding Products
productsList.add(new Product(1,"HP Laptop",25000f));
productsList.add(new Product(2,"Dell Laptop",30000f));
productsList.add(new Product(3,"Lenevo Laptop",28000f));
productsList.add(new Product(4,"Sony Laptop",28000f));
productsList.add(new Product(5,"Apple Laptop",90000f));
// count number of products based on the filter
long count = productsList.stream()
.filter(product->product.price<30000)
.count();
System.out.println(count);
}
}
Output:
The Stream API enables us to gather outcomes in a variety of formats. Results can be obtained as sets, lists, or maps, allowing for manipulation of the elements.
Java Stream Example : Convert List into Set
Example
import java.util.*;
import java.util.stream.Collectors;
class Product{
int id;
String name;
float price;
public Product(int id, String name, float price) {
this.id = id;
this.name = name;
this.price = price;
}
}
public class JavaStreamExample {
public static void main(String[] args) {
List<Product> productsList = new ArrayList<Product>();
//Adding Products
productsList.add(new Product(1,"HP Laptop",25000f));
productsList.add(new Product(2,"Dell Laptop",30000f));
productsList.add(new Product(3,"Lenevo Laptop",28000f));
productsList.add(new Product(4,"Sony Laptop",28000f));
productsList.add(new Product(5,"Apple Laptop",90000f));
// Converting product List into Set
Set<Float> productPriceList =
productsList.stream()
.filter(product->product.price < 30000) // filter product on the base of price
.map(product->product.price)
.collect(Collectors.toSet()); // collect it as Set(remove duplicate elements)
System.out.println(productPriceList);
}
}
Output:
[25000.0, 28000.0]
Java Stream Example: Convert List into Map
Example
import java.util.*;
import java.util.stream.Collectors;
class Product{
int id;
String name;
float price;
public Product(int id, String name, float price) {
this.id = id;
this.name = name;
this.price = price;
}
}
public class JavaStreamExample {
public static void main(String[] args) {
List<Product> productsList = new ArrayList<Product>();
//Adding Products
productsList.add(new Product(1,"HP Laptop",25000f));
productsList.add(new Product(2,"Dell Laptop",30000f));
productsList.add(new Product(3,"Lenevo Laptop",28000f));
productsList.add(new Product(4,"Sony Laptop",28000f));
productsList.add(new Product(5,"Apple Laptop",90000f));
// Converting Product List into a Map
Map<Integer,String> productPriceMap =
productsList.stream()
.collect(Collectors.toMap(p->p.id, p->p.name));
System.out.println(productPriceMap);
}
}
Output:
{1=HP Laptop, 2=Dell Laptop, 3=Lenevo Laptop, 4=Sony Laptop, 5=Apple Laptop}
Method Reference in stream
Example
import java.util.*;
import java.util.stream.Collectors;
class Product{
int id;
String name;
float price;
public Product(int id, String name, float price) {
this.id = id;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public float getPrice() {
return price;
}
}
public class JavaStreamExample {
public static void main(String[] args) {
List<Product> productsList = new ArrayList<Product>();
//Adding Products
productsList.add(new Product(1,"HP Laptop",25000f));
productsList.add(new Product(2,"Dell Laptop",30000f));
productsList.add(new Product(3,"Lenevo Laptop",28000f));
productsList.add(new Product(4,"Sony Laptop",28000f));
productsList.add(new Product(5,"Apple Laptop",90000f));
List<Float> productPriceList =
productsList.stream()
.filter(p -> p.price > 30000) // filtering data
.map(Product::getPrice) // fetching price by referring getPrice method
.collect(Collectors.toList()); // collecting as list
System.out.println(productPriceList);
}
}
Output:
[90000.0]
Java Stream Specializations
Java Streams API provides specific stream variants optimized for processing primitive data types effectively. IntStream is designed for integers, LongStream for long integers, and DoubleStream for doubles. These tailored streams deliver improved efficiency and include specialized operations tailored for numeric calculations, making them ideal for handling primitive numerical data.
- Specialized Functions
Streams designed for handling numeric data provide enhanced functionality compared to the general Stream interface. These streams offer specialized methods that simplify mathematical calculations directly on primitive data streams.
- Reduction Operations
Reduction operations represent a form of terminal operation that merges all elements within the Stream to produce a singular outcome. They utilize a binary operator to iteratively execute a function, passing on the outcome as the initial argument of the operator for each consecutive application of the function to the subsequent stream element. This approach is particularly effective for condensing or consolidating numerical data.
Java Stream: File Operation
The Java Streams API, which was first introduced in Java 8, offers an effective and clear method for managing streams of data, such as files. Here, "streams" denote a series of elements that enable both sequential and parallel aggregate operations, distinct from InputStream and OutputStream in I/O streams.
Utilizing the Streams API for data manipulation with files includes the tasks of reading data from files, processing it either line by line or in batches, and frequently saving the outcomes to a different file. This functionality is commonly accomplished through the Files class within the java.nio.file package, which harmonizes effectively with the Streams API.
Example
// Import the necessary classes for handling I/O operations and managing lists
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
// Define a public class named FileReadExample
public class FileReadExample {
// Define a private static method that filters strings by length and converts them to uppercase
private static List<String> filterAndConvertToUpper(List<String> lines, int length) {
// Create a new ArrayList to store filtered and modified strings
List<String> filteredStrings = new ArrayList<>();
// Iterate over each string in the list provided
for (String line : lines) {
// Check if the length of the string equals the specified length
if (line.length() == length) {
// Convert the string to uppercase and add it to the list of filtered strings
filteredStrings.add(line.toUpperCase());
}
}
// Return the list of filtered and converted strings
return filteredStrings;
}
// Define the main method, which is the entry point for the program
public static void main(String[] args) {
// Specify the path to the file that will be read
String fileName = "D://hello world//CustomFileReader.txt";
// Initialize a new ArrayList to store the lines read from the file
List<String> lines = new ArrayList<>();
// Use try-with-resources to ensure the BufferedReader is closed properly
try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
String line;
// Read each line of the file until no more lines are found
while ((line = br.readLine()) != null) {
// Add each line to the list of lines
lines.add(line);
// Print out each line that is read, for debugging purposes
System.out.println("Read line: " + line);
}
// Call the filterAndConvertToUpper method to process the lines and store the result
List<String> filteredStrings = filterAndConvertToUpper(lines, 5);
// Print out the list of filtered and converted strings
System.out.println("Filtered strings with length 5 (converted to uppercase): " + filteredStrings);
} catch (IOException e) {
// Catch and print details of any IOException that occurs during file reading
e.printStackTrace();
}
}
}
Input:
hello
world
Yes
12345
Spaces
Java!
1234
ABCDE
Output:
Read line: hello
Read line: world
Read line: Yes
Read line: 12345
Read line: Spaces
Read line: Java!
Read line: 1234
Read line: ABCDE
Filtered strings with length 5 (converted to uppercase): [HELLO, WORLD, 12345, JAVA!, ABCDE]
Example
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;
import java.util. Stream.Stream;
// Class to demonstrate writing to a file
class FileWriterExample {
// Main method as the entry point of the application
public static void main(String[] args) {
// Array of strings to be written to the file
String[] phrases = { "Sample", "Text", "For", "File", "Write" };
// Path to the file where the text will be written
String filePath = "D://hello world//CustomFileReader.txt";
// Attempt to open the file and write phrases to it
try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(Paths.get(filePath)))) {
// Writing each string from the array to the file using a stream
Stream.of(phrases).forEach(writer::println);
// Notify user of successful write operation
System.out.println("Text has been successfully written to the file.");
} catch (IOException e) {
// Handle potential IO exceptions such as file not found or access issues
e.printStackTrace();
}
}
}
Output:
Text has been successfully written to the file.