
Java 8: No more loops - GarethX
http://www.deadcoderising.com/java-8-no-more-loops/
======
anton_gogolev
In C#, this is significantly more elegant:

    
    
        public IList<String> getDistinctTags(IEnumerable<Article> articles) 
        {  
            return articles.SelectMany(a => a.Tags).Distinct().ToList();
        }
    

The entire LINQ "empire" (.NET 3.5) is built on top of IEnumerable<T> which
was around since .NET 2.0. Streams seem to be very artificial; why not rely on
Iterable<>?

Oh, and no "yield" in Java.

~~~
djb_hackernews
"Significantly" is a bit dramatic when we are talking about the difference
between a single extra method call.

One of the benefits of the Java version is it is easier to understand if you
don't have a Java background but do have an FP background. With your C#
example you'd need to find the documentation to find out what SelectMany does
(which is probably just a helper method that abstracts a map and flatMap call)

~~~
iwwr
>One of the benefits of the Java version is it is easier to understand if you
don't have a Java background but do have an FP background.

Are there professional programmers with only FP and no imperative language
experience?

------
obstinate
I really want to like functional programming, but the functional version of
each of these seems less readable and more verbose.

~~~
remon
This was exactly what I was thinking when I read the code. The goal should not
be to remove loops. As a language construct there is nothing wrong with loops
itself. The goal should be to make more readable and maintainable code,
preferably without increasing verbosity. The functional alternatives posted
here are not actually code quality improvements and should not be presented as
such.

~~~
BFay
I welcome the functional features, but I have to agree that these specific
examples are ugly compared to the more familiar alternatives.

Maybe this will look more readable after getting used to it, but I'd much
rather be looking at Clojure or Scala for now.

~~~
bollockitis
Out of curiosity, could you share an example of how this compares to Clojure
or Scala? I am not familiar with either.

~~~
markc
Here's a quick version in Clojure. I'm sure it can be done cleaner than this..

    
    
      (def articles
        [{:title "title1" :author "author1" :tags #{:Java :t2 :t3}}
         {:title "title2" :author "author1" :tags #{:Jvxa :t2 :t3}}
         {:title "title3" :author "author3" :tags #{:Java :t3}}])
      
      ;; find the first article in the collection that has the tag “Java”.
      (first (filter #(contains? (:tags %) :Java) articles))
      ;; ==> {:tags #{:t2 :Java :t3}, :title "title1", :author "author1"}
      
      ;;get all the elements that match instead of just the first
      (filter #(contains? (:tags %) :Java) articles)
      ;; ==> ({:tags #{:t2 :Java :t3}, :title "title1", :author "author1"}
              {:tags #{:Java :t3}, :title "title3", :author "author3"})
      
      ;;group all the articles based on the author.
      (group-by :author articles)  ;; cheating?
      ;; ==> {"author1"
                 [{:tags #{:t2 :Java :t3}, :title "title1", :author "author1"}
                  {:tags #{:Jvxa :t2 :t3}, :title "title2", :author "author1"}],
              "author3"
                 [{:tags #{:Java :t3}, :title "title3", :author "author3"}]}
      
      ;;find all the different tags used in the collections
      (apply clojure.set/union (map :tags articles))
      ;; ==> #{:Jvxa :t2 :Java :t3}

~~~
codygman

        (group-by :author articles)
        groupBy ((==) `on` author) articles
    

What's wrong with cheating? :P

------
mythz
Java's one of the worst language examples of using FP collections I've seen.
Even with hindsight I still find this to be uglier and unnecessarily more
verbose than it needs to be.

E.g. same Example in Dart:

    
    
        class Article {
          String title;
          String author;
          List<String> tags;
          Article(this.title, this.author, this.tags);  
        }
    
        Article getFirstJavaArticle() =>
            articles.firstWhere((x) => x.tags.contains("Java"));
    
        List<Article> getAllJavaArticles() =>
            articles.where((x) => x.tags.contains("Java"));
    
        List<String> getDistinctTags() =>
            articles.expand((x) => x.tags).toSet().toList();
    

Can even be shorter without the Optional typing, but it's more readable to be
explicit to have them. Dart benefits from having Collection and Stream mixins
so you always get a rich API on Dart's collections.

If anyone's interested to comparing FP collections in different languages,
I've ported C# 101 LINQ examples in:

    
    
      - Swift    https://github.com/mythz/swift-linq-examples
      - Clojure  https://github.com/mythz/clojure-linq-examples
      - Dart     https://github.com/dartist/101LinqSamples

~~~
kuschku
And your example doesn’t even tell what it’s doing.

I’d have to look up what .expand, .where etc means, while Java just uses the
standard FP names that every CompSci student knows.

~~~
kasey_junk
Where makes sense if you think of it from a SQL perspective which I _think_
has more widespread use than the corresponding FP terms (ie lots of developers
don't have a CompSci background, but few of them haven't used trivial SQL).

------
edgyswingset
The first example is actually a poor way to do it, IMO. Even if behind the
scenes, these are implemented lazily (like C# LINQ), it may not be obvious
what's going on to someone else who isn't familiar with the API. I'd opt for
the for() loop each time when it's something like halting when you find what
you're looking for.

~~~
anon4
The for loop is actually a poor way to do it, IMO. Even if behind the scenes,
these are implemented via conditional gotos (like C), it may not be obvious
what s going on to someone else who isn't familiar with the syntax. I'd opt
for the if-goto loop each time when it's something like halting when you find
what you're looking for.

To wit: You can expect others to be familiar with basic features of the
language and ecosystem, or prepared to learn them.

------
aaronetz
In the last example's "for" loop, a Set would probably be clearer and more
efficient than a List for gathering distinct elements, at least for large data
sets. I haven't tried the functional Java yet, but I wonder if using
Collectors.toSet() and skipping the distinct() stage would be better?

------
SeanDav
Any thoughts on performance differences between loops and streams?

My gut says that loops, being a more primitive concept are likely to perform
better in most situations. In addition I just find loops easier to reason
about, but that is probably purely personal.

~~~
kasey_junk
I have not looked at the java8 constructs surrounding this.

This is largely implementation specific. For instance, the .net LINQ to object
implementations are largely syntactic sugar around loops (that is they compile
to the same thing). Similarly, for loops are frequently just syntactic sugar
around while loops.

~~~
azth
Have they improved the implementation recently? I have not benchmarked myself,
but according to [1], they are slower than the equivalent loop-based code.

    
    
        [1] http://arxiv.org/pdf/1406.6631v2.pdf

~~~
kasey_junk
This paper rightly points out that there will be overhead of object creation
and potentially virtual calls (though that will be very JIT dependent). That
said, my cursory examination (and it was very cursory) of their benchmark for
C# is that they are really benchmarking the time difference between the
iterator of an IEnumerable (or maybe IList, don't have an ability to decompile
it right now) and the highly optimized case of looping through an array (which
is literally one of the most highly optimized tasks on modern commodity
hardware).

On one hand, it does prove their point that in certain very specialized cases
(looping through an array with no abstraction atop it), you will have
significant performance penalties in the generic iterator case.

On the other, I'm not sure I would attribute this to LINQ. I'm reasonably
certain (and in these cases the space "reasonably" represents could have a
truck driven through it) if you were to write the same code as a foreach loop
using the same iterator and generic collections you wouldn't see significant
performance differences. I'm definitely confident in most "real world" uses,
where you are already using generic collections and iterators, you should bias
towards using the LINQ implementation (assuming you believe it is better code)
until definitive performance testing proves otherwise. For instance, in the
case of the sum of squares, that looks like classic loop unrolling
optimizations not being applied which any indirection in the looping code can
prevent.

Further, they show that there already exist optimization libraries that can
eliminate much of the overhead.

I will say, I'm quite impressed by the java results on this benchmark.

Also, I didn't write any tests to prove any of this, so could be wildly off
the mark. Further, I've spent more time than i ever wanted either hand
translating or writing macros to, translate high level collections code into
while loops. But that was in an extremely performance sensitive environment.

------
skywhopper
The examples feel very much like Ruby to me. In a good way. This sort of
chaining of operations also feels very natural for someone thinking in terms
of a chain of Unix commands piped together.

However, having that explicit "stream()" signifier is a very Java-y thing to
do and appears to ask the programmer to decide how best to compile the given
line. I would expect the compiler should be doing that work for us.

------
carsongross
This demonstrates a major problem with development of Java since the
Collections work (which was fantastic): the libraries suffer from over-
engineering and surface far too much implementation flavor in the API.

Who _cares_ about streams? Who _cares_ about Optional? We just want to filter
a list in a clear, terse manner. (Some people _do_ care about streams and
Optional, and I wish them well, but that's orthogonal to the question at
hand.)

Consider the examples given. Here they are implemented in Gosu:

    
    
      getFirstJavaArticle() : Article {  
        return articles.firstWhere(\ article -> article.Tags.contains("Java"))
      }
    
      getAllJavaArticles() : List<Article> {  
        return articles.where(\ article -> article.Tags.contains("Java"))
      }
    
      groupByAuthor() : Map<String, List<Article>> {  
        return articles.partition( \ article -> article.Author )
      }
    
      public getDistinctTags() : Set<String> {  
        return articles.*Tags.toSet()
      }
    

(I cheated a bit on the last one by just using a Set, but that's more
appropriate and communicates the uniqueness of the elements in the collection
to the API consumer.)

Beyond the dot-star flatmap operator, there isn't anything very fancy going
on: just closures being passed to methods, returning familiar classes that
don't require additional transformation to pass on to the rest of the world.

It's too bad, because this is certainly good enough. As Jack Nicholson said:
What if this... is as good as it gets?

------
Proleps
why not use:

    
    
      public final class Article{
        public final String title;
        public final String author;
        public final List<String> tags;
        public Article(String title, String author, List<String> tags) {
          this.title = title;
          this.author = author;
          this.tags = tags;
        }
      }
    

Getters don't seem very useful on an immutable object.

~~~
organsnyder
If you ever want to change the implementation of Article, you'd break anyone
that was using that part of your API. If you use getters, you can change your
implementation without breaking the consumers of your API.

For instance, let's say that you don't want to store the author's name as a
string anymore, and want to store a reference to an Author object. If you have
a getAuthor() method, you can change it from a simple getter to instead call
author.getName(), preserving your public-facing API.

~~~
Proleps
> If you ever want to change the implementation of Article, you'd break anyone
> that was using that part of your API. If you use getters, you can change
> your implementation without breaking the consumers of your API.

Then it wouldn't be immutable, if I can change the implementation I can also
create a mutable version.

Edit example

    
    
      public class Article {
          private final String title;
          private final String author;
          private final List<String> tags;
    
          private Article(String title, String author, List<String> tags) {
              this.title = title;
              this.author = author;
              this.tags = tags;
          }
    
          public String getTitle() {
              return title;
          }
    
          public String getAuthor() {
              return author;
          }
    
          public List<String> getTags() {
              return tags;
          }
      }
    
      public class MutableArticle extends Article {
          private String title;
          private String author;
          private List<String> tags;
    
          public MutableArticle() {
              super(null, null, null);
          }
    
          public String getTitle() {
              return title;
          }
    
          public void setTitle(String title) {
              this.title = title;
          }
    
          public String getAuthor() {
              return author;
          }
    
          public void setAuthor(String author) {
              this.author = author;
          }
    
          public List<String> getTags() {
              return tags;
          }
    
          public void setTags(List<String> tags) {
              this.tags = tags;
          }
    
      }

~~~
organsnyder
Making a class immutable doesn't mean that the _implementation_ is fixed. If
you need to change your implementation to store data differently, the
consumers of your API shouldn't need to be modified. The following
modification to your first class would still be immutable:

    
    
      public class Article {
        private final Author author;
        ...
        public String getAuthor() {
          return author.getName();
        }
      }
    

Also, your first class isn't fully immutable—getTags should be implemented as
follows:

    
    
      /**
       * @return Unmodifiable list of tags
       */
      public List<String> getTags() {
        return Collections.unmodifiableList(tags);
      }

~~~
Proleps
> Also, your first class isn't fully immutable—getTags should be implemented
> as follows:

True. It would be nice if Java had some immutable collection classes that
don't have mutable methods. A method that gets a List<String> made with
Collections.unmodifiableList(tags), doesn't know that it is actually
immutable.

------
spullara
Here is another example, porting a spellchecker from Python to Java 8.

[https://github.com/jmoy/norvig-
spell/blob/master/java/src/ma...](https://github.com/jmoy/norvig-
spell/blob/master/java/src/main/java/spellcheck/Main.java)

------
glifchits
Constructing a collection of things is just one case where a for loop is nice.
Would be nice to see some more interesting examples of how we can use streams.

------
wodude
I've been doing this in Java WebObjects for a decade

tagList = articles.tags.@flatten.@unique.@sort

------
nsxwolf
I still find streams far more difficult to teach to a new programmer than
loops.

------
Beltiras
All I could think: it's still sunk in too much architecture....

~~~
pron
Too much architecture for what? For bankings? For medical devices? For the
safety-critical avionics software? For high-frequency trading? For
manufacturing control? For weapon-systems? For power-plant command and
control? For government ERP running on mainframes? Because Java is used for
all of these things.

Yes, some bits might be too architected for your MVP web app that you're going
to re-write in a year (and even that depends mostly on the libraries you're
using; there are plenty of lean libraries for the web-startup crowd).

------
hristov
So Java is trying to slowly turn into Haskell.

~~~
kasey_junk
More like it is trying to catch up with C#.

------
bitL
...aaand the obfuscation of Java begins!

------
codygman
Here's the Haskell equivalent for anyone curious (Beware of curry[0]!):

    
    
        data Article = Article { title :: String
                               , author :: String
                               , tags :: [String]
                               } deriving (Show)
        
        articles = [ Article "Functional Java" "James Gosling" ["functional"]
                   , Article "Practical java" "James Gosling" ["enterprise","architechture"]
                   , Article "Imperative Haskell" "Simon P Jones" ["imperative", "purely imperative"] ]
        
        firstJavaArticle = headMay . filter (isInfixOf "Java" . title)
        
        allJavaArticles = filter (isInfixOf "Java" . title)
        
        groupArticlesByAuthor = groupBy ((==) `on` author)
        
        distinctArticleTags = nub . join . map tags
    

Full working code example with code imports and type signatures:

    
    
        import Data.List (isInfixOf, groupBy, nub)
        import Safe (headMay)
        import Data.Function (on)
        import Control.Monad (join)
        
        data Article = Article { title :: String
                               , author :: String
                               , tags :: [String]
                               } deriving (Show)
        
        articles :: [Article]
        articles = [ Article "Functional Java" "James Gosling" ["functional", "functional"]
                   , Article "Practical java" "James Gosling" ["enterprise","architechture"]
                   , Article "Imperative Haskell" "Simon P Jones" ["imperative", "purely imperative"] ]
        
        firstJavaArticle :: [Article] -> Maybe Article
        firstJavaArticle = headMay . filter (isInfixOf "Java" . title)
        
        -- implemented in terms using allJavaArticles (NOTE: This IS performant in Haskell and IIUC due to stream fusion will only iterate once. Did not verify though.)
        firstJavaArticle' :: [Article] -> Maybe Article
        firstJavaArticle' = headMay . allJavaArticles
        
        allJavaArticles :: [Article] -> [Article]
        allJavaArticles = filter (isInfixOf "Java" . title)
        
        groupArticlesByAuthor :: [Article] -> [[Article]]
        groupArticlesByAuthor = groupBy ((==) `on` author)
        
        distinctArticleTags :: [Article] -> [String]
        distinctArticleTags = nub . join . map tags
        
        main = undefined
    
    

0:
[http://en.wikipedia.org/wiki/Currying](http://en.wikipedia.org/wiki/Currying)

[http://tech.pro/tutorial/2011/functional-javascript-
part-4-f...](http://tech.pro/tutorial/2011/functional-javascript-part-4-f..).

[https://www.haskell.org/haskellwiki/Currying](https://www.haskell.org/haskellwiki/Currying)

