Parallelism in the software industry has become pretty common place since it’s the best way to achieve speed. The release of Java 8 has added some extremely beneficial features to the language. While those are not the main topic of this post, they are important for the concept of Java Streams and Java Parallel Streams. Just to add some scope, lets take a look at some of those other features.
Anyone with experience writing in Java knows that multiple inheritance cannot be performed in Java (C++ on the other hand supports multiple inheritance). It is a true statement that multiple inheritance can be badly abused, but I firmly believe there are some cases where it makes sense. Java 8 provides the ability to add default implementations of methods on Java interfaces. This does not add multiple inheritance to the language, however it does allow for a pattern that developers can use to imitate multiple inheritance.
First Class Methods
Lambda expressions are another important feature of Java 8. They provide a similar functionality as First Class Methods. Lambda expressions can be thought of as anonymous functions, and viewed as purely functional. What does this mean? This means that they have some input and they should always produce output relative to their inputs. Think of a method that computes averages. You might pass that method a list of values to compute an average on. The internal workings of that method do not change, but the inputs and output do. Functional programming can also be a methodology. You don’t need to write lambdas to write functional code. Writing code in a functional manor can lead to ease when testing. It’s much easier to test code that is functional because in a test you want to have control over the inputs and outputs.
The Java Streams API uses many of the features described above to execute it’s goals. Streams provides a much cleaner interface for working with Java Collections. Imagine that you want to operate over a List of data. You might write an enhanced for loop to operate on the data, however their is a more concise way to do this in Java 8. Java 8 Streams provide some really great default functionality. The ability to filter a collection is as simple as providing a method or lambda so filter on.
.filter(e -> e.getGender() == Person.Sex.MALE)
.forEach(e -> System.out.println(e.getName()));
The Streams API also provides the ability to perform reductions out of the box.
Integer totalAgeReduce = roster
(a, b) -> a + b);
You may have noticed a pattern in the content above. It should not be a surprise that the new features above were released together. They all work in union to enhance Java and bring elements of functional languages to Java. I know personally I am really excited about all of them, but especially the notion of “Methods as first class citizens”… Ran into the multiple inheritance issue quite a few time!
This last topic build on top of all of the above. Scalability, contention, synchronization have all been issues to deal with when working with parallelism. Java 8 Parallel Streams attempts to simplify these issues by abstracting them. The concept seems note worthy, but it is important to look at all sides of the rubix cube. I point out the niceties of Parallel Streams, but there are also many posts out there describing real issues with abstracting parallelism. It’s easy to imagine that abstracting parallelism leads to a lack of control… The point is: use the right tool for the job. Check out this post describing what I mentioned above:
Here is an example of parallel streams in action:
double average = roster
.filter(p -> p.getGender() == Person.Sex.MALE)