Java 8 Streams, an introduction

in #programming7 years ago

Java 8 (1.8) provided us with the Stream API, a streams is a sequential sequence of elements (Java objects) that have support for multiple specific operations. An operation is a stream method that accepts a callback that will be invoked on each item on the stream.

from the docs

 Classes to support functional-style operations on streams of elements, such as map-reduce transformations on collections. 

Using streams we can streamline our work when working on large collections of elements, we can reduce amount of code and make our remaining code more readable resilient.

Creating a stream is easy, the Stream class provides us with several static methods to quickly instantiate a stream, the simplest way is using the .of method which accepts a vector of objects of the same type

Stream.of(1, 2, 3, 4, 5);

which is approximately the equivalent of writing

int[] array = {1, 2, 3, 4, 5};

except that our numbers are wrapped inside a stream and we can chain operations on it

So lets say we want to traverse an array and print it's element,  up until now we would've written it as so

int[] arr = {1, 2, 3, 4, 5};
for (int i=0; i<arr.length; i++) {
   System.out.println(arr[i]);
}  // 1, 2, 3, 4, 5

And now using streams, we will use the .forEach operation method, this operation accepts a Consumer function (yeah, there are no functions in Java, a Consumer is just an anonymous class that implements an .accept method which will be called by the operation) will be invoked once for each element, in order

Stream.of(1, 2, 3, 4, 5).forEach(new Consumer<Integer>() {
   @Override
   public void accept(Integer integer) {
       System.out.println(integer);
   }
});  // 1, 2, 3, 4, 5

Looks a bit messy, luckily we can utilize Lambdas and shorten the code to

Stream.of(1, 2, 3).forEach((number) -> {
   System.out.println(number);
});

We can concatenate streams, suing the .concat static method

Stream streamA = Stream.of("ray", "peter");
Stream streamB = Stream.of("egon", "winston");
// and now combine them
Stream.concat(streamA, streamB).forEach((name) -> System.out.println(name));
// "ray", "peter", "egon", "winston"

This method accepts 2 streams and links them together in order

The Stream class also contains an implementation of the builder pattern, which allows you to build a stream in multiple steps

Stream.builder().add(12).add(23).add(34).build().forEach((n) -> System.out.println(n));
// 12, 23, 34

We don't always need the Stream class to get a stream, other parts of the Java standard library were updated to provide us with streams, the biggest edition is the added .stream method to the Collection interface and the implementation detail to get streams from all the classes that implement this interface, which are .. (from the Javadoc)

 AbstractCollection, AbstractList, AbstractQueue, AbstractSequentialList, AbstractSet, ArrayBlockingQueue, ArrayDeque, ArrayList, AttributeList, BeanContextServicesSupport, BeanContextSupport, ConcurrentLinkedDeque, ConcurrentLinkedQueue, ConcurrentSkipListSet, CopyOnWriteArrayList, CopyOnWriteArraySet, DelayQueue, EnumSet, HashSet, JobStateReasons, LinkedBlockingDeque, LinkedBlockingQueue, LinkedHashSet, LinkedList, LinkedTransferQueue, PriorityBlockingQueue, PriorityQueue, RoleList, RoleUnresolvedList, Stack, SynchronousQueue, TreeSet, Vector 

That's a lot.

Here's how we would get a stream from a list

List<String> namesList = new ArrayList<>();
namesList.add("moe");
namesList.add("larry");
namesList.add("curly");
namesList.stream().forEach(name -> {
   System.out.println(name);
});

But what about maps? well, maps don't implement the Collection interface and they're not ordered so we can't directly get a stream from a map, however maps provide us with helper methods that return stored values and keys as collections, and these collections are "streamable"

people.keySet().stream(); // .keySet returns a Set of keys
people.values().stream(); // .values returns a Collection of values
people.entrySet().stream(); // .entrySet returns a Set of Entry objects that acts as key/value pairs

for example

people.entrySet().stream().forEach((Map.Entry<String, Integer> person) -> {
   String name = person.getKey();
   int age = person.getValue();
});

Java also provide parallel streams by calling the .parallelStream, these streams work upon their stored items in parallel, utilizing threading to shorten potential long, time consuming operation, lets look at the following example

people.entrySet().parallelStream().forEach((Map.Entry<String, Integer> person) -> {
   try {
       String name = person.getKey();
       int age = person.getValue();
       Thread.sleep(1000);
       System.out.println(name + " : " + age);
   } catch (InterruptedException ex) {
       ex.printStackTrace();
   }
});

it's a bit heavy, so let's go step by step on what's happening here 

  1. we have a set of people, we use a parallel stream to run them at parallel
  2. each callback accesses it's own Thread and sleeps for 1000 milliseconds (1 second)
  3. wake up and then print the key and value

Using regular streams we would wait for n seconds for this code to complete (n being the amount of stream items), however since we used a parallel stream, we would wait for a little more than a second for the code to finish. 

It should be noted that parallel streams incur high overhead and resources due to it's concurrent nature, and should mostly be used when dealing with time consuming jobs. using them on simple tasks such will only slow things down, use it where you can afford it.


Done! (for now) This is just a small portion of what Java has to offer for streams, there are still a lot that needs to be talked about such as Operators (.map, .filter etc..) and Collectors which allow to to create new, mutated copies of our data, group them in different ways and more, so there's a lot to go over on.

Sort:  

Congratulations @svarog! You received a personal award!

1 Year on Steemit

Click here to view your Board of Honor

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @svarog! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 2 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!

Coin Marketplace

STEEM 0.19
TRX 0.15
JST 0.029
BTC 63117.29
ETH 2601.03
USDT 1.00
SBD 2.76