• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Tim Cooke
  • Campbell Ritchie
  • Paul Clapham
  • Ron McLeod
  • Liutauras Vilda
Sheriffs:
  • Jeanne Boyarsky
  • Rob Spoor
  • Bear Bibeault
Saloon Keepers:
  • Jesse Silverman
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
Bartenders:
  • Piet Souris
  • Al Hobbs
  • salvin francis

Streams vs loops Isnt it better to use loops in nearly all cases

 
Ranch Hand
Posts: 680
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I like the look of streams, they look neat, dare I say sexy. But from a performance point of view I have found loops are better. Now we have moved into NoSql we are ending up with huge amounts of data to throw around. So apart from a very few cases such as in concurrency issues, using Maps. I have gone back to loops.
So my point is thinking totally in terms of performance, if performance is something that you are thinking of, its best to use loops.

So purely thinking in terms of performance ,  can anyone think of a case where they would use a stream rather than a loop. A case I have is an a example



Which I use to handle a race condition

I hope this stimulates a debate, although I am sure it has been debated before.
 
Marshal
Posts: 74375
334
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It all depends what you want your application to do. If raw performance is your No 1 priority, then maybe you are better off with loops. But ost people don't want raw performance as their top priority.
Remember that loops use an imperative style and Streams a declarative style, so Streams are likely to be much easier to maintain. And the cost of throwing silicon at a performance problem is likely to be less than the cost of a developer's salary.
 
Saloon Keeper
Posts: 13396
296
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I prefer streams in nearly all cases, except when your loop has side effects that apply to a field or local variable.

Functional programming is very interesting from a performance standpoint. Functional code often declares what final result you want to achieve, without specifying how to achieve it. That leaves a lot of room for optimization by the underlying implementation. Some functional code can theoretically be much more performant than an old-fashioned for-loop:

This piece of code very clearly states that you want a list of African capitals, without specifying how to get it.

Here is the imperative approach:

In the second piece of code, you're telling the runtime what to do every step of the way: Take the first country. Check whether it's African. If it is, add it to the list. Take the second country. Check whether it's African... etc. There's no room for optimization, other than making your system faster.

In the first piece of code, we can replace our system with a magic ball that will instantaneously retrieve all African capitals, and it will be correct. This seems far-fetched, but instead of a magic ball, imagine a piece of specialized hardware that can process stream elements concurrently and collect them into a list without the overhead of thread scheduling.

So, even if your streams run more slowly NOW, they may not always. Functional code also more succinctly expresses what final result you are interested in.

Finally, in most cases it doesn't matter that streams are slower. Performance bottlenecks are often in parts of the code where you don't expect them. You must find them by careful profiling of your application. Even then, the solution to the bottleneck is almost invariably to improve the time complexity of the algorithm or use dynamic programming or caching, not replacing functional code with imperative code.
 
Sheriff
Posts: 22510
122
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tony Evans wrote:So purely thinking in terms of performance ,  can anyone think of a case where they would use a stream rather than a loop.


Purely thinking in terms of performance, you shouldn't use a for-each loop with an ArrayList, as it creates an extra Iterator instance that you don't need (for LinkedList it's a different matter). However, this is a case of premature optimization. You may win several nanoseconds by making your code less easy to read. For me, I'd always prefer over or the even more performant

I have reasoned here about the performance of streams vs loops. My conclusion there was the same as it is here - readability over performance unless a) the stream is the bottleneck in your code, or b) every nanosecond counts. I haven't found such a case yet though.
 
Campbell Ritchie
Marshal
Posts: 74375
334
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I am not sure about your having a size loop variable, Rob, just in case there is a concurrent modiciation. Of course, I have read this and know the most performant way to write a loop is,
 
Rob Spoor
Sheriff
Posts: 22510
122
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:I am not sure about your having a size loop variable, Rob, just in case there is a concurrent modiciation.


In which case a for-each loop will throw a ConcurrentModificationException. I'm expecting my Lists to not be modified while I'm iterating over them.

Regarding your example: I know about RandomAccess, but I've never bothered using it to loop in a different way. It's just plain nasty. (And your second loop can be turned into a for-each loop, as that compiles to the same code you wrote.)
 
Tony Evans
Ranch Hand
Posts: 680
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi thanks for the replies, I think raw performance is my number one priority,  especially now working in the cloud we are loading huge amounts of data into collections, and every bit of performance you can squeeze out is important.
I dont think loops are that hard to read and maintain. When streaming first came out, like many others I mistook stream for speed.
 
Stephan van Hulst
Saloon Keeper
Posts: 13396
296
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tony Evans wrote:I think raw performance is my number one priority,  especially now working in the cloud we are loading huge amounts of data into collections, and every bit of performance you can squeeze out is important


You're probably really overestimating the importance of these micro-optimizations. Have you already profiled your application?
 
Marshal
Posts: 26912
82
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tony Evans wrote: Hi thanks for the replies, I think raw performance is my number one priority...



But remember that your post title included the phrase "in nearly all cases". That means that the answer to your original post is still "No". Now, you may have a special case where you need to look at performance carefully, in which case yes, you should certainly look at performance carefully. That may or may not involve rewriting loops but Java does a variety of optimization under the radar, so it's a surprisingly difficult thing to do.
 
Marshal
Posts: 5146
321
IntelliJ IDE Python Java Linux
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In recent times I have worked on very very very very very high performance applications and I don't recall at any time a bottleneck in the system being the result of a particular type of iteration. As Stephan mentions, unless you have already profiled your system and have identified the iteration implementation as your bottleneck, then you're most likely trying to solve the wrong problem here.

My advice is to use the iteration style that you and your team (if you're working in a team) are most familiar and comfortable working with. Then forget about it and move on.
 
Campbell Ritchie
Marshal
Posts: 74375
334
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Rob Spoor wrote:. . . your example: . . . It's just plain nasty. . . .

Isn't it! I was trying to write the worst code I could
 
Sheriff
Posts: 16669
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Agree with everyone who has commented about premature optimization. Don't optimize a program with gut feelings and guesses; programmers really suck at that. Use a profiler instead.
 
Rob Spoor
Sheriff
Posts: 22510
122
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:

Rob Spoor wrote:. . . your example: . . . It's just plain nasty. . . .

Isn't it! I was trying to write the worst code I could


Don't worry, I'm aware of that. But it's still nasty
 
Saloon Keeper
Posts: 24557
168
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Don't assume ANYTHING without benchmarking. I haven't looked at the stream mechanism closely enough to determine what actual overhead it has, but I can tell you that "loop unrolling" is one of the most basic and common optimizations done by optimizing compilers. And a stream is itself an unrolled loop.

And I repeat: Don't assume ANYTHING without benchmarking. I have spent years specializing in optimizations and the one thing I learned long ago is that the actual bottlenecks are almost never where you "know" they're going to be. And frequently, swapping out high-level code algorithms will offer you FAR more efficiency than micro-structuring your code. In fact, about the only time I actually saw a mainframe get taken down by software the problem was completely obliterated by changing a single option setting on the program itself.

And finally, don't assume that performance is the most important goal. We're not talking bogging down a single multi-million dollar mainframe anymore - and when we were, we very rarely got that concerned with micro-optimization even then. These days, you have Elastic computing and cheap hardware and unless you've got an absolute train wreck in performance, the amount of money your employer can save by simply throwing more hardware at a problem is going to vastly outweigh the expense and time spent paying you do twiddle the small stuff.
 
Greenhorn
Posts: 6
1
  • Likes 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I don't see this obvious topic being mentioned by others, but PARALLEL streams can speed up an operation on a larger set of data considerably. (An "easy" way to do parallelism.) It can do this because of the functional style of operations in streams - a set of operations on one element is independent from the operations on all the other elements.

One practical example: I have a utility searching for a certain filename recursively in a directory tree (expensive disk reads). This was sped up dramatically "simply" by moving from for() to .stream().parallel(). (I quote simply because the operations did take some rewriting for the declarative style.)

Parallelism does its thing with some processing overhead, which only pays off for larger data sets, so if in doubt I construct some experiment to determine if this would be worth it for my specific data elements and the operations on them. My very rough rule-of-thumb is that with fairly simple/quick operations I should consider parallelism from 100 elements and upwards (yes, that small). If operations are time consuming, even less may be appropriate. (I think for simple/quick operations on less than 100 elements, it's hardly worth it to worry about the difference between loops and (sequential) streams unless profiling shows a bottleneck - as per others' posts.) Again, all this is very dependant on each specific case's details, so if in doubt, do the benchmarking.

As an aside, I started doing some work in Clojure a few monts ago. Functional operations on collections are the default way things happen here, so that part is very familiar to someone having used streams. It is interesting how this functional approach, with the benefits of immutability for parallelism, has changed my thought processes around constructing algorithms. (I loved the elegance of the compact expressivity of streams when Java 8 came out, and Clojure has the same sort of expressivity for the WHOLE language.) Still, if performance is your priority this environment is probably not your first choice... yet.
 
Rob Spoor
Sheriff
Posts: 22510
122
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
One warning about using parallel streams: if I recall correctly, parallel streams are executed in the common ForkJoinPool. That does not have unlimited capacity, so if you're going to handle many concurrent requests, using parallel streams may introduce a bottleneck that will actually lead to a performance decrease. Before you introduce parallel threads, it's wise to perform some tests before and after, to make sure that parallel streams are indeed an improvement.
 
Derc Zbrojvic
Greenhorn
Posts: 6
1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Rob Spoor wrote:One warning about using parallel streams: if I recall correctly, parallel streams are executed in the common ForkJoinPool. That does not have unlimited capacity...


Pros and cons everywhere :-) Thanks for pointing out some implications.
 
Rob Spoor
Sheriff
Posts: 22510
122
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You're welcome.
 
reply
    Bookmark Topic Watch Topic
  • New Topic