In simple
terms, stream is a sequence of data items that are processed one at a time.
Streams in Java are similar to streams in UNIX. You can pass output stream of
one program to input stream of other.
Java8
implements streams in java.util.stream package. Stream<T> represents a
sequence of items of type T. Streams API provides number of methods to achieve
UNIX pipe kind of functionality in Java.
Streams are
used to manipulate collection of data in declarative way. You just tell stream
what you want, stream does that for you (Less worries for developer). In
addition to this, streams can be processed parallel (You can achieve parallel
behavior using multi threading, which is complex and possibility of errors) to
leverage your multicore architectures.
Following
application shows simple example of using streams.
Suppose I want
to get all employee first names whose salary is > 40000 and sort them by first
name. You no need to do lot of coding to solve above problem. Following streams
code snippet do this for you.
List<String>
firstNames = employees.stream().filter((Employee emp) -> emp.getSalary()
> 40000).sorted(comparing(Employee::getFirstName)).map(Employee::getFirstName).collect(Collectors.toList());
public class Employee { private int id; private String firstName; private String lastName; private int age; private String city; private double salary; public Employee(int id, String firstName, String lastName, int age, String city, double salary) { super(); this.id = id; this.firstName = firstName; this.lastName = lastName; this.age = age; this.city = city; this.salary = salary; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } @Override public boolean equals(Object employee) { if (Objects.isNull(employee)) return false; if (!(employee instanceof Employee)) return false; Employee emp = (Employee) employee; return id == emp.id; } @Override public int hashCode() { return Objects.hash(id, firstName, lastName, age); } @Override public String toString() { return String.format("%s(%s,%d,%f)", firstName, city, age, salary); } }
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import static java.util.Comparator.comparing; public class SortEmployee { public static void main(String args[]) { Employee emp1 = new Employee(1, "Hari Krishna", "Gurram", 26, "Bangalore", 40000); Employee emp2 = new Employee(2, "Joel", "Chelli", 27, "Hyderabad", 35000); Employee emp3 = new Employee(3, "Shanmukh", "Kummary", 28, "Chennai", 76000); Employee emp4 = new Employee(4, "Harika", "Raghuram", 27, "Chennai", 75000); Employee emp5 = new Employee(5, "Sudheer", "Ganji", 27, "Bangalore", 90000); Employee emp6 = new Employee(6, "Rama Krishna", "Gurram", 27, "Bangalore", 100000); Employee emp7 = new Employee(7, "PTR", "PTR", 27, "Hyderabad", 200000); Employee emp8 = new Employee(8, "Siva krishna", "Ponnam", 28, "Hyderabad", 55000); Employee emp9 = new Employee(9, "Gopi", "Battu", 28, "Hyderabad", 78000); Employee emp10 = new Employee(10, "Anil", "Tadavarthi", 28, "Hyderabad", 30000); List<Employee> employees = new ArrayList<>(); employees.add(emp1); employees.add(emp2); employees.add(emp3); employees.add(emp4); employees.add(emp5); employees.add(emp6); employees.add(emp7); employees.add(emp8); employees.add(emp9); employees.add(emp10); List<String> firstNames = employees.stream() .filter((Employee emp) -> emp.getSalary() > 40000) .sorted(comparing(Employee::getFirstName)) .map(Employee::getFirstName).collect(Collectors.toList()); System.out.println(firstNames); } }
Output
[Gopi, Harika, PTR, Rama Krishna, Shanmukh, Siva krishna, Sudheer]
Lets closely
look at following statement.
List<String>
firstNames = employees.stream().filter((Employee emp) -> emp.getSalary()
>
40000).sorted(comparing(Employee::getFirstName)).map(Employee::getFirstName).collect(Collectors.toList());
a.
First
I get a stream for list of employees.
b.
Filter
list of employees on filed salary
c.
Sort
employees on firstName
d.
Extract
firstName field of employees
e.
Collect
result as list.
Suppose you
had 1GB of employee data, to speed up processing you want to use all processors
of your system. Stream provide parallel processing functionality, instead of
calling stream method on collection, call parallelStream method.
List<String>
firstNames = employees.parallelStream().filter((Employee emp) ->
emp.getSalary() > 40000).sorted(comparing(Employee::getFirstName)).map(Employee::getFirstName).collect(Collectors.toList());
What can I do using streams
a. You
can perform data processing effectively
Streams support number of operations like sort,
map, collect, map, reduce etc., to process data. One good thing is you can
process stream data in sequence (or) in parallel
b.
Pipelining
Almost all stream operations return stream as
output, so you can pass output stream of one method as input stream to another
method. Which is similar like pipelining.
c. Internal
iteration
Suppose you want to apply some operation on a
collection, you no need to iterate collection and process each and every
element. Stream operations do the iteration behind the scenes for you.
Note:
1.
If
you generate stream from an ordered collection like ArrayList, stream preserves
ordering.
2. You can consume stream only once. If you tries
to use stream, which is already consumed, java.lang.IllegalStateException
thrown
import java.util.*; import java.util.stream.Stream; public class Test { public static void main(String args[]) { List<Integer> list = Arrays.asList(2, 3, 5, 7, 11); Stream<Integer> stream = list.stream(); stream.forEach(System.out::println); System.out.println("Calling stream second time"); stream.forEach(System.out::println); } }
When you ran
above program, you will get following output.
2
Exception in
thread "main" 3
5
7
11
Calling
stream second time
java.lang.IllegalStateException:
stream has already been operated upon or closed
at
java.util.stream.AbstractPipeline.sourceStageSpliterator(AbstractPipeline.java:274)
at
java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at
miscellaneous.Test.main(Test.java:14)
No comments:
Post a Comment