6 ms·
A lot of comments here focus on the readability, conciseness, and expressiveness of Java streams compared to other languages. IMO they are missing the point and
by manjalyc 3y ago
A lot of comments here focus on the readability, conciseness, and expressiveness of Java streams compared to other languages. IMO they are missing the point and are just reiterating the same complaints everyone has about the Java language in x different ways.
Java streams bring real benefits compared to other mature languages. My favorite is that sequential streams can be efficiently parallelized with a single operation, .parallel(), and sequentialized back, .sequential(), on any stream without having to configure a single knob manually (although you certainly can), an equivalent I am unaware of in any other matured language. These make operations such as .collect() and its mutable reductions leverage multiple threads for effectively 0 additional programming time.
edit: A lot of people are focusing on my favorite feature of parallelizing or serializing a stream with a single command, which apparently you can also do in C#, that was just an example guys. Other cool things you can do with Java streams natively now is leverage virtual threads (take that C#), use them asynchronously with completable futures, define how elements are accessed/gathered in streams via spliterators, etc. Streams in Java are very composable (not just as in composition, but as in utility), and enable leveraging nearly every other part of the language natively. In other mature languages, streams are very rigid and feel non-composable. I'm not saying that everything is impossible in other languages, but that in Java streams feel like a first-class citizen.
- neonsunset 3y agoC# had PLINQ (aka arr.AsParallel()) since the time immemorial. It also works quite well with picking the right parallelization strategy and is very similar in its use to Rust Rayon's .par_iter().
- ynik 3y agoThat's a common feature nowadays, not unique to Java. C# has had `enumerable.AsParallel()` since .NET 4.0 (2010). Rust has rayon `input.par_iter()`.
- manjalyc 3y agoDoes C# allow you to convert a sequential stream into a parallel stream, or do streams have to be parallelized when initiated? Genuinely asking, I do not know C#
- paavohtl 3y agoThat's literally what AsParallel() does.
- capableweb 3y ago> Rust has rayon `input.par_iter()` rayon is a 3rd party library though, not part of the language itself, compared to the Java streams discussed here. With C# I'm not sure if .NET can be called a library or not? All C# tooling ships with .NET by default or not?
- EnergyAmy 3y agoThat's just the way Rust does things, like with the `rand` crate. Lean stdlib, easy dependency management. For the purposes of "does Rust do X", popular crates should be included in that consideration.
- capableweb 3y agoOk, so then what is this discussion about? Java Streams have existed basically forever, as a 3rd party library, but that doesn't matter here in our conversation about Java language features, where 3rd party libraries somehow changes what the language is...
- EnergyAmy 3y agoI guess it's nice for Java that they did this, but the OP's assertion that no other language handles this as nicely doesn't really stand. For example, this quote: > In other mature languages, streams are very rigid and feel non-composable I'd like to see some motivating examples that make me say to myself, "Yeah, Java's got a neat trick there".
- dackerlunghack 3y ago[dead]
- neonsunset 3y agoWhether it ships with it or not is, however, irrelevant. As long as the library is sufficiently popular and accepted by community, it can be seen as the advantage of a particular platform/language. In this regard, while it is nice that PLINQ and various `Parallel`-related APIs come out of box in C#, it is a marginal difference with Rust where building parallel loops is `cargo add rayon` away.
- marginalia_nu 3y agoAs much as I like Java, I don't think this is a good point. Even C lets you do this[1] [1] https://en.wikipedia.org/wiki/OpenMP https://en.wikipedia.org/wiki/OpenMP
- manjalyc 3y agoMy point was that it is built into Java streams and requires 0 extra configuration or work on the programmer's end. Not that you can't parallelize in other languages.
- marginalia_nu 3y agoWell yeah, this is true for openmp as well. In my experience, parallel streams rarely deliver a substantial performance boost. There are cases where they do, but it's more the exception than the rule. The overhead from the streams API, along with the synchronization penalties means it mostly only makes sense for coarse grained I/O laden operations.
- manjalyc 3y agoOpenMP is not a language? You can take any language and add libraries to achieve a specific goal, my point is that Java streams are first-class citizens compared to other matured programming languages that also enable leveraging other aspects of the Java ecosystem without running into the rough edges you will with OpenMP. Also, that is definitely not the rule? If your problem is parallelizable by nature, parallelism provides massive speedups. Overhead from parallelizing a stream is minimal (effectively nonexistent) now if you leverage Java virtual threads (JDK 21). Additionally, most problems are not parallelizable, yes, but most solutions consist of individual steps and there is a high likelihood that at least one of those steps will benefit from parallelism. Java streams can switch between .parallel() and .sequential() execution on the go. You almost certainly don't want to leverage stream parallelism for most I/O operations, unless you leverage Java's Completeable Futures and Managed Blocking (but any gains here are probably minimal anyways) but the point is that you can leverage them, because streams in Java are a first class citizen.
- vbezhenar 3y agoHow often is it used? I write a lot of Java and I never used this feature. For me, it made streams implementation unbearably complex, to the point that I can't read its sources for a feature that I probably will never use. I, personally, wish they never implement this parallel feature. For me JDK would be better without it.
- manjalyc 3y agoStarting to program with Java streams is weird because you are utilizing functional constructs in a language that historically had little notion of them. When I first started using them it felt worthless when I could achieve the same thing in classic OOP faster (and often run it faster too). But after a while you get a feel for the fluid style programming streams enable (and imo cleaner code). These days with ChatGPT, its probably a lot easier to get started. With that said, you should almost always write a stream thinking only sequentially first, then identify steps which can benefit from .parallel() and only parallelize those steps. Its leveraging .parallel() efficiently that provides an advantage at run-time and why I tend to use it.
- vbezhenar 3y agoI guess I was unclear, but I wrote specifically about parallel streams. Of course I use ordinary streams on every day basis. But using parallel stream in a server application which processes dozens of other requests simultaneously and runs on a server with dozen of other applications (very typical use-case for Java) just makes very little sense, because CPUs are already loaded and it'll just result with more context switches. I could imagine use-case for that (very urgent request which must be completed at expense of other requests and includes heavy collection processing), but I've yet to encounter it.
- manjalyc 3y agoYea, I don't imagine native stream parallelism will help when CPUs are already loaded. Presumably you're using Spring or Rx, in which case you probably can leverage reactive streams and/or Managed Blockers, but thats really just taking advantage of async patterns and not necessarily parallelism. The only case I could envision having a concrete benefit is if you used your own fork-join pool leveraging virtual threads instead of the global fork-join pool to prevent platform threads from hogging CPU, and then used reactive streams that leveraged the virtual threads. Although this would (theoretically) raise responsiveness, it would almost certainly come at the cost of throughput. All that is to say, parallelism generally only provides as much value as you have idle CPU cores.
- misja111 3y agoScala has all of the benefits you are listing, plus more, and natively, with a more concise and composable syntax.
- manjalyc 3y agoYep, and I love writing Scala as much as I hate writing Java, but I wouldn't say its maturity is in the same league as Java, C/C++, etc.
- dkarl 3y agoA language doesn't just keep getting better and better with age. "Maturity" is about achieving a a level of stability and quality in language features, tooling, runtime, library ecosystem, etc. Scala and Java share the same runtime and library ecosystem, and Scala is arguably more mature in its language features, since Java has been forced to add features (and incur extra complexity) playing catch-up to newer JVM languages (including Scala.) Both languages actually suffer from maturity in their tooling, because their standard build and dependency management tools (maven and sbt) are outdated and crufty, while newer languages such as Go and Rust have tooling that was built more recently, with the benefit of more recent experience.
- kagakuninja 3y agoOne of the strengths of Scala is also a weakness. They aren't afraid to break things and make changes that are not backwards compatible. The Scala devs have been much more careful about breakage than in the past, so I think they have reached a good compromise between stability and evolution. The masterful execution of the Scala 3 upgrade is an example. Java by contrast will never clean up the bad, inconsistent or obsolete cruft in the language. If it is really important for you to run ancient JARs on Java 21, then the Java approach is superior.
- KptMarchewa 3y agoIn practice, such frivolous parallelism is frowned upon and rarely useful.
- belter 3y agoOne of the most important comments in this thread.
- yazaddaruvala 3y ago+1 almost all uses of parallel streams I’ve seen in Java caused issues in reliability or performance. Not because of any reason other than the people using it choose to use the feature before learning about the feature.
- EnergyAmy 3y agoDo you have an example or a link to examples that makes you say "In other mature languages, streams are very rigid and feel non-composable"? I'd be interested in seeing what advantages it has over something like Rayon.
- delusional 3y ago> My favorite is that sequential streams can be efficiently parallelized with a single operation, .parallel(), and sequentialized back, .sequential() That's not actually true. .parallel and .sequential set a state flag for the entire stream. A stream that is opened, parallelized, then sequentalized, will actually just execute sequentially [1] [1]: https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/stream/package-summary.html#Parallelism https://docs.oracle.com/en/java/javase/14/docs/api/java.base...
- riku_iki 3y ago> My favorite is that sequential streams can be efficiently parallelized with a single operation, .parallel() I would never use it because I can't reason what is going under the hood, and if performance will improve or dramatically decrease because all parallel machinery has significant overhead compared to vectorized single thread logic.
- smrtinsert 3y agoDid I get here before AbstractFactoryBean meme? The famous class no one actually used?
- javier2 3y agoI actually really like the java streams, sure it could be better, but it is actually extremely useful. The parallell() though is very bad as its too easy to ruin your entire app. Its backed by the Common ForkJoinPool which many have no control over, and if Java was unable to detect CPU Count, it could be set to unbounded.