Let's talk about STREAMS !!
Tags: java, beginners, tutorial, career
Published: 2020-08-08 09:40:02

![wave](https://raw.githubusercontent.com/MartinHeinz/MartinHeinz/master/wave.gif)
 
--- 

Hey there!


## *In this article I will be talking about Streams in Java and how they help in writing neat and compact production codes.*

But before diving into Streams let us talk  a little about **Functional Programming** 

We as Java developers are constantly grilled about Java's verbose nature and how to even print a single word we have to write about 5-8 lines of code. :sob:

Well this was the scenario before JAVA 8 came into the picture.
With the inclusion of Functional Programming the JAVA code's verbosity can be reduced to around 70%. :open_mouth:

Coming back to my point lets see what is Functional Programming.

 ---


## :dart: What is Functional Programming :question:

Functional programming (also called FP) is a way of thinking about software construction by creating pure functions. It avoid concepts of shared state, mutable data observed in Object Oriented Programming.

Functional languages emphasizes on expressions and declarations rather than execution of statements. Therefore, unlike other procedures which depend on a local or global state, value output in FP depends only on the arguments passed to the function.

 ---

## :dart: Characteristics of Functional Programming:

Functional programming method focuses on results, not the process
Emphasis is on what is to be computed

* Data is immutable
* Functional programming Decompose the problem into 'functions
* It is built on the concept of mathematical functions which uses conditional expressions and recursion to do perform the calculation
* It does not support iteration like loop statements and conditional statements like If-Else

 ---

## :dart:  The benefits of functional programming:

* Allows you to avoid confusing problems and errors in the code
* Easier to test and execute Unit testing and debug FP Code.
* Parallel processing and concurrency
* Hot code deployment and fault tolerance
* Offers better modularity with a shorter code
* Increased productivity of the developer
* Supports Nested Functions
* Functional Constructs like Lazy Map & Lists, etc.
* Allows effective use of Lambda Calculus.

---

So we have a basic idea of Functional Programming now!
Lets see how this is implemented in  JAVA Streams 
 
Simply put, streams are **wrappers** around a data source, allowing us to operate with that data source and making bulk processing convenient and fast.

A stream does not store data and, in that sense, is not a data structure. It also never modifies the underlying data source.

This functionality – java.util.stream – supports functional-style operations on streams of elements, such as map-reduce transformations on collections.

 ---

:white_check_mark: Before beginning with Streams lets note down some important concepts :

1.Stream is a flow of data derived from a collection
2.Stream can create a pipeline  of function that can be evaluated
3.Data in Stream is Lazy Evaluated
4.Stream can transform data but cannot mutate it.

 ---

:dart: [NOTE] -  Stream is not a Data Structure.Also the data structure on which you are creating the  stream is not changed at all.The Stream just (kinda) makes a copy of it and performs some actions on its own copy.
 
 ---



**Well that's all fine but how to create a Stream** ? :confused:

## :dart: Stream Creation:

:heavy_check_mark: Let’s first obtain a stream from an existing array:

```
private static Dev[] arrayOfDevs = {
    new Dev(1, "Steve Rogers", 100000.0), 
    new Dev(2, "Anthony Stark", 200000.0), 
    new Dev(3, "Bruce Wayne", 300000.0)
};

Stream.of(arrayOfDevs);

```
 ---

:heavy_check_mark: We can also obtain a stream from an existing list:

```
private static List<Dev> devList = Arrays.asList(arrayOfDevs);
devList.stream();
```
3. And we can create a stream from individual objects using Stream.of():

```
Stream.of(arrayOfDevs[0], arrayOfDevs[1], arrayOfDevs[2]);
```
 ---
 
:heavy_check_mark: Or simply using Stream.builder():

```
Stream.Builder<Dev> devStreamBuilder = Stream.builder();

devStreamBuilder.accept(arrayOfDev[0]);
devStreamBuilder.accept(arrayOfDev[1]);
devStreamBuilder.accept(arrayOfDev[2]);

Stream<Dev> devStream = devStreamBuilder.build();

```
 ---

Ok so now we know how to create a Stream.  :sunglasses:
But whats the use of a Stream if we cant play around with it. 

  ---

## :dart: Stream Operations:

 Let’s now see some common usages and operations we can perform on and with the help of the stream support in the language.

:heavy_check_mark: forEach:


forEach() is simplest and most common operation; it loops over the stream elements, calling the supplied function on each element.

The method is so common that is has been introduced directly in Iterable, Map etc:
```
@Test
public void whenIncrementSalaryForEachDev_thenApplyNewSalary() {    
    devList.stream().forEach(d -> d.salaryIncrement(10.0));
    
    assertThat(devList, contains(
      hasProperty("salary", equalTo(110000.0)),
      hasProperty("salary", equalTo(220000.0)),
      hasProperty("salary", equalTo(330000.0))
    ));
}
```

This will effectively call the salaryIncrement() on each element in the devList.

forEach() is a terminal operation, which means that, after the operation is performed, the stream pipeline is considered consumed, and can no longer be used.

 ---


:heavy_check_mark: map

map() produces a new stream after applying a function to each element of the original stream. The new stream could be of different type.

The following example converts the stream of Integers into the stream of Devs:

```

@Test
public void whenMapIdToDevs_thenGetDevStream() {
    Integer[] devIds = { 1, 2, 3 };
    
    List<Dev> devs = Stream.of(devIds)
      .map(devRepository::findById)
      .collect(Collectors.toList());
    
    assertEquals(devs.size(), devIds.length);
}
```

Here, we obtain an Integer stream of dev ids from an array. Each Integer is passed to the function devRepository::findById() – which returns the corresponding Dev object; this effectively forms an Dev stream.

 ---
 
:heavy_check_mark:  collect
We saw how collect() works in the previous example; its one of the common ways to get stuff out of the stream once we are done with all the processing:

```
@Test
public void whenCollectStreamToList_thenGetList() {
    List<Dev> devs = devList.stream().collect(Collectors.toList());
    
    assertEquals(devList, devs);
}
```

collect() performs mutable fold operations (repackaging elements to some data structures and applying some additional logic, concatenating them, etc.) on data elements held in the Stream instance.

The strategy for this operation is provided via the Collector interface implementation. In the example above, we used the toList collector to collect all Stream elements into a List instance.

 ---

:heavy_check_mark: filter

Next, let’s have a look at filter(); this produces a new stream that contains elements of the original stream that pass a given test (specified by a Predicate).

Let’s have a look at how that works:

```
@Test
public void whenFilterDevs_thenGetFilteredStream() {
    Integer[] devIds = { 1, 2, 3, 4 };
    
    List<Dev> devs = Stream.of(devIds)
      .map(devRepository::findById)
      .filter(e -> e != null)
      .filter(e -> e.getSalary() > 200000)
      .collect(Collectors.toList());
    
    assertEquals(Arrays.asList(arrayOfDevs[2]), devs);
}
```
In the example above, we first filter out null references for invalid dev ids and then again apply a filter to only keep devs with salaries over a certain threshold.

 ---

:heavy_check_mark: toArray
We saw how we used collect() to get data out of the stream. If we need to get an array out of the stream, we can simply use toArray():
```
@Test
public void whenStreamToArray_thenGetArray() {
    Dev[] devs = devList.stream().toArray(Dev[]::new);

    assertThat(devList.toArray(), equalTo(devs));
}
```

The syntax Dev[]::new creates an empty array of Devs – which is then filled with elements from the stream.

 --- 

## :dart: [NOTE]


## **Lazy Evaluation**

One of the most important characteristics of streams is that they allow for significant optimizations through lazy evaluations.

Computation on the source data is only performed when the terminal operation is initiated, and source elements are consumed only as needed.

All intermediate operations are lazy, so they’re not executed until a result of a processing is actually needed.

For example, consider the findFirst() example we saw earlier. How many times is the map() operation performed here? 4 times, since the input array contains 4 elements?

```
@Test
public void whenFindFirst_thenGetFirstDevInStream() {
    Integer[] devIds = { 1, 2, 3, 4 };
    
    Dev devs= Stream.of(devIds)
      .map(devRepository::findById)
      .filter(e -> e != null)
      .filter(e -> e.getSalary() > 100000)
      .findFirst()
      .orElse(null);
    
    assertEquals(devs.getSalary(), new Double(200000));
}
```
Stream performs the map and two filter operations, one element at a time.

It first performs all the operations on id 1. Since the salary of id 1 is not greater than 100000, the processing moves on to the next element.

Id 2 satisfies both of the filter predicates and hence the stream evaluates the terminal operation findFirst() and returns the result.

No operations are performed on id 3 and 4.

Processing streams lazily allows avoiding examining all the data when that’s not necessary. This behavior becomes even more important when the input stream is infinite and not just very large.

  ---

Java Streams Api is a very large topic and i have tried  my best to fit as much as possible in this post.
Please refer to the below links for more in depth knowledge.

:point_down:

[Link for reference-1](https://www.geeksforgeeks.org/stream-in-java/#:~:text=A%20stream%20is%20a%20sequence,Arrays%20or%20I%2FO%20channels.)

 [Oracle docs ](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html)

[Baeldung link](https://www.baeldung.com/java-8-streams)

[Devoxx Youtube](https://www.youtube.com/channel/UCCBVCTuk6uJrN3iFV_3vurg)
 
---

Some of my other posts:


| Concept   |      link    |  
|----------|:-------------:|
| Java Access Modifiers |  [goto Article](https://dev.to/the_unconventional_coder/java-concept-of-the-day-1jim) | 
| Java Generics |  [goto Article](https://dev.to/the_unconventional_coder/java-concept-of-the-day-oec)     |  
|Java Regex     | [goto Article](https://dev.to/the_unconventional_coder/lets-talk-about-regex-3npd)
| Java Streams Api | [goto Article](https://dev.to/the_unconventional_coder/lets-talk-about-streams-2bdf) | 

 ---

Please leave a :heart: if you liked this article.
A 🦄 would be great.
And let me know in the discussions panel if you have any suggestions for me.
And do leave a link to any resource  on Java Streams Api that you know  of ,that can help others   and  i will  add it  to the post.


Have a Good Day! :smiley: