1. Innovations in Java 8: Functional programming
With the release of Java 8, the language gained powerful support for functional programming. You could even say it gained long-awaited support for functional programming. Coding became faster, although the code was more difficult to read 🙂
Before learning functional programming in Java, we recommend that you understand three things well:
- OOP, inheritance and interfaces (Levels 1-2 in the Java Core quest).
- Default method implementations in an interface.
- Inner and anonymous classes.
The good news is that you don't have to know all this to use many of the features of functional programming in Java. The bad news is that it will be difficult to understand exactly how everything is arranged and how everything works without knowing about anonymous inner classes.
In the upcoming lessons, we will focus on how easy and simple it is to use Java's functional programming features, without a deep understanding of how it works.
It takes months to understand all the nuances of functional programming in Java. You can learn to read such code in a few hours. So we suggest starting small. Even if it's with I/O streams.
2. I/O streams: stream pipelines
Do you remember that once upon a time you learned about I/O streams: InputStream
, OutputStream
, Reader
, Writer
etc.?
There were stream classes that read data from data sources, such as FileInputSteam
, and there were intermediate data streams that read data from other streams, such as InputStreamReader
and BufferedReader
.
These streams could be organized into data processing pipelines. For example, like this:
FileInputStream input = new FileInputStream("c:\\readme.txt");
InputStreamReader reader = new InputStreamReader(input);
BufferedReader buff = new BufferedReader(reader);
String text = buff.readLine();
It's important to note that in the first few lines of code, we're just constructing a chain of Stream
objects. The data hasn't passed through the pipeline yet.
But as soon as we call the buff.readLine()
method, the following will happen:
- The
BufferedReader
object calls theread()
method on theInputStreamReader
object - The
InputStreamReader
object calls theread()
method on theFileInputStream
object - The
FileInputStream
object starts reading data from the file
In other words, there is no movement of data along the stream pipeline until we start calling methods like read()
or readLine()
. The mere construction of the stream pipeline does not drive data through it. The streams themselves do not store data. They only read from others.
Collections and streams
Starting with Java 8, it became possible to get a stream to read data from collections (and not only from them). But this is not the most interesting thing. It actually became possible to easily and simply construct complex chains of data streams. And in doing so, the code that previously took 5-10 lines could now be written in 1-2 lines.
Example of finding the longest string in a list of strings:
Finding the longest string |
---|
|
|
3. Stream
interface
Java 8's extended support for streams is implemented using the Stream<T>
interface, where T
is a type parameter that indicates the type of data being passed in the stream. In other words, a stream is completely independent of the type of data it passes.
To get a stream object from a collection, just call its stream()
method. The code looks roughly like this:
Stream<Type> name = collection.stream();
In this case, the collection will be considered the stream's data source, and the Stream<Type>
object will be a tool for obtaining data from the collection in the form of a data stream.
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
Stream<String> stream = list.stream();
By the way, you can get a stream not only from collections, but also from arrays. To do this, you need to use the Arrays.stream()
method. For example:
Stream<Type> name = Arrays.stream(array);
In this case, the array will be considered the data source for the stream called name
.
Integer[] array = {1, 2, 3};
Stream<Integer> stream = Arrays.stream(array);
No data is moved when the Stream<Type>
object is created. We simply got a stream object in order to start building a stream pipeline.
GO TO FULL VERSION