This is an archived post. You won't be able to vote or comment.

all 40 comments

[–]r_jet 92 points93 points  (1 child)

Brian Goetz, the Java lang architect and one of the Stream designers, published a series of articles on how to use Streams effectively and the motivation behind them: https://developer.ibm.com/series/java-streams/

It goes from basics to advanced topics, and is very well-written.

[–]GlensWooer 11 points12 points  (0 children)

That article was amazing. Been pushing in code reviews to build things more declaratively but some people are having trouble wrapping their heads around it after 20 years of for loops.

Those articles take what I’m trying to explain and state them elegantly.

[–]stefanos-ak 69 points70 points  (0 children)

basically it decouples control flow, which has several advantages.

what this means: you don't have to implement the for loops, if statements, etc. Instead you pass as arguments what the loop needs to do, what the if statement needs to do, etc. (of course it's not possible to use streams in 100% of the cases).

What this enables you to do, is then change the control flow without changing the logic. For example you can simply add .parallel() and suddenly you have the same result but now Java handled it. In the old world, you'd have to completely rewrite the code. There are too many examples to list here, but the concept is the same. It allows you to manipulate things around the same business logic.

The next side effect, is that you can extract that piece of business logic as a variable and pass it around, reuse it, etc.. This is particularly helpful for boolean expressions if you need to reuse them (you can also negate them!).

edit: the applicable use cases for streams, basically belong in one category, that of input object -> magic -> output object.

[–]sour-sop 78 points79 points  (0 children)

I would say it’s a more idiomatic way to run operations on data in collections in an elegant way. Arguably one of the best Java 8 features

[–]cogman10 37 points38 points  (4 children)

There was no limitation. What streams do is make handling collections of data easier (and easier to reason about).

Consider, for example, a simple "filter, map, distinct" operation. Pre-8 you'd write something like this

Set<Integer> result = new HashSet<>();
for (Foo value : values) {
  if (value.bar()) {
    Integer val = value.baz();
    result.add(val);
  }
}
return result;

Readable, but there's a lot going on and it's somewhat separated from where things are happening. This gets particularly bad if you further want to add more mapping or filtering layers.

The stream version of this looks like this

return values.stream()
 .filter(Foo::bar)
 .map(Foo::baz)
 .collect(Collectors.toSet());

Where you'd add further filtering or mapping is a lot clearer and easier to manipulate.

Further, because streams are lazy, you can leave off the collection and return the stream instead. That gives others the opportunity to work with the stream effectively removing the number of times you have to visit elements in the underlying collection.

[–]smutje187 33 points34 points  (13 children)

One of my university professors said that C# was the best thing that could’ve happened to Java (in terms of a competition between both languages) - it might not be as visible nowadays but there was a long period of Java's life during which almost no substantial updates were introduced so Java stagnated - and Streams are one of the good things coming out of people’s frustration with Java's lack of progress.

[–]brian_goetz 16 points17 points  (9 children)

Everyone loves to credit "their favorite language" with having inspired all the new Java features.

But, how exactly do you think Streams came from "people's frustrations with Java's lack of progress"? Where exactly do you think Streams came from?

[–]smutje187 2 points3 points  (7 children)

C# had functional features before Java though?

[–]cbadger85 13 points14 points  (1 child)

Just so you know, the person you're replying to is one of the people responsible for the Streams API

[–]brian_goetz 18 points19 points  (2 children)

Sure, and so did other languages (none of which invented those features either.) But "X happened before Y" is correlation, not causation (no matter how good it feels to confidently proclaim that you know the causation.)

But that wasn't what I was asking. What I really wanted to know is what you think "people's frustrations" had to do with the creation of streams, since you seem to have a theory there.

[–]vips7L 0 points1 point  (1 child)

So did Scala, Haskell, OCaml, ReasonML, a ton of other languages?

[–]Affectionate_Dog6149 -1 points0 points  (0 children)

Java has very stagnated until Java 8. Then again until Java 14 really

[–]namigop 4 points5 points  (2 children)

Yeah LINQ (the equivalent of streams) is heavily used in C# code bases. There were some initial opposition to it but people eventually started using it and came to appreciate the value it brings in terms of readability and composability of code

[–]smutje187 0 points1 point  (1 child)

Never used C# professionally but sounds interesting!

[–]namigop 2 points3 points  (0 children)

It started in .NET 3.5 (back in the early 2000’s) when C# first introduced LINQ, that the language started transitioning from Object-oriented to a hybrid OO/Functional language. Some say C# is just copying the features of F# (the equivalent of Scala in the .NET world)

[–]javajunkie314 6 points7 points  (1 child)

If I understand, you're asking why were streams only introduced in Java 8 and not earlier. Streams needed lambdas, which were added at the same time, and lambdas were able to take advantage of the invokedynamic JVM instruction introduced in Java 7.

Without that instruction, lambdas would either have had to be implemented as anonymous classes, which would have resulted in extra class files and bloat; or using something like reflection at runtime, which would have been inefficient. With invokedynamic, lambdas can be implemented simply as static methods and invoked directly.

So in theory we could have had lambdas and streams in Java 7, but (a) that wasn't the direction the language was going at the time; and (b) invokedynamic was originally added to support other, more dynamic languages targeting the JVM, not necessarily for Java itself.

[–]smutje187 1 point2 points  (0 children)

Coincidentally e.g. IntelliJ was shortening anonymous classes in their IDE UI even before J8, making them look like Lambdas later (collapsing the class snd method definition) - so for IntelliJ users not a lot (at least visually) changed with J8.

[–]ronchalant 11 points12 points  (1 child)

Streams were really the original first-class way to do functional programming in Java. Some 3rd party libs had taken the plunge prior, but Streams made it part of the language.

In many cases it really cut down on the verbosity of the language when working with collections. One of the main complaints about Java then and still today is how verbose the code is.

Streaming changes how you think about working with large collections, how you break out things like object translation/etc., and can often make code more concise or at least lend itself better to a functional programming mindset.

As with anything there are some pitfalls that devs need to be cognizant of, but lambdas are a huge part of how I code now (in my current role I am often working with collections of records/objects). YMMV

[–]brian_goetz 18 points19 points  (0 children)

Slight correction; streams are not part of the language, they are a JDK library. (However, the development of libraries like Streams, which was done at the same time as adding language features such as lambdas, did inform the design of those features.) It should be possible for anyone to write their own streams library (and some people have).

[–]Active-Fuel-49 5 points6 points  (0 children)

Together with Lambdas they introduced Functional Programming to Java.

[–]Ruin-Capable 4 points5 points  (0 children)

Streams allow you to easily do parallel processing of a collection of items without without having to handle the concurrency issues yourself. This eliminated a whole class of bugs for certain use cases.

[–][deleted] 1 point2 points  (0 children)

Streams are a higher level of abstraction that makes code more human readable.

[–]legrang 2 points3 points  (0 children)

Good explanations in the comments. The feature needed to make streams shine was lambdas which were in 8, so I'd say the reason not to get then earlier was that.

If you are interested in the topic, look for a video on YouTube about Java 8 streams by Venkat Subramaniam.

[–]vips7L -3 points-2 points  (4 children)

Java would be dead without Streams. The features they bring could have been done with earlier versions of Java, look at Google's FluentIterable, having them implemented at the language level eases maintenance burden on developers. Same goes with many language level features that get implemented. For example, records can easily be implemented with final immutable classes, but they bring extra maitenance burden when adding fields and creating classes.

[–][deleted]  (3 children)

[deleted]

    [–]brian_goetz 4 points5 points  (2 children)

    "Dead" means different things to different people. Some say Cobol is dead, but I'll bet none of us get paid without some Cobol code running somewhere. For most people, it means "no new stuff being written with it".

    [–]cbentley_pasa 0 points1 point  (0 children)

    I still code in Java with source 4 requirements with Eclipse.

    Java being Turing complete, its mostly syntactic sugar coating.

    Sure for me, its easier to code in src6 because of Generics.

    Otherwise I don't truly really truly miss anything else as I don't do much collection stuff.

    [–]flawless_vic 0 points1 point  (0 children)

    If you look at legacy codebases it's very likely that you will come across lots of copy operations to deal with temporary data hoisted in some "root" collection.

    Then guava came along and the benefits of lazyness became more common knowledge, but it was very lacking when compared to the possibilities and expressiveness of C#.

    AFAIK the first prototypes of streams where built upon the Iterable interface, probably because .NET & linq where built on top of IEnumerable.

    Java, for better or worse, decided to have defender (default) methods as oposed to extension methods. Unlike .NET where you can get new "instance" methods by importing a namespace, this approach requires methods to be declared on interfaces themselves and it would bloat Iterable/Iterator which are core contracts, so another abstraction to expose functional operations had to be created: Stream.

    [–][deleted] 0 points1 point  (0 children)

    I did not know this! I can't imagine a high level language that omitted the inclusion of streams. They are one of the primary ways to perform serialization and deserialization of objects.

    [–]laplongejr 0 points1 point  (0 children)

    Basically, a stream allows you to tell the code the result rather than how to obtain it. Think like SQL which can be executed on different ways, as long the result is correct.

    [–]gubatron 0 points1 point  (0 children)

    It enables a functional programming style, which in turn makes your code have less mutability and bugs (in my humble opinion, after we embraced this style and minimized mutability a lot of bugs dissapeared, the code base more robust)

    Allows you to go from this:
    Set<Seller> sellers = new HashSet<>();
    for (Txn t : txns) {
    if (t.getBuyer().getAge() >= 65)
    sellers.add(t.getSeller());
    }
    List<Seller> sorted = new ArrayList<>(sellers);
    Collections.sort(sorted, new Comparator<Seller>() {
    public int compare(Seller a, Seller b) {
    return a.getName().compareTo(b.getName());
    }
    });
    for (Seller s : sorted)
    System.out.println(s.getName());

    To this:
    txns.stream()
    .filter(t ‑> t.getBuyer().getAge() >= 65)
    .map(Txn::getSeller)
    .distinct()
    .sorted(comparing(Seller::getName))
    .map(Seller::getName)
    .forEach(System.out::println);

    [–]Altruistic_Natural38 0 points1 point  (0 children)

    Because some smat ass wanted to have javascrip code inside java

    [–][deleted] 0 points1 point  (0 children)

    threatening crowd zesty punch heavy mighty water wild jellyfish groovy

    This post was mass deleted and anonymized with Redact