• Post Reply Bookmark Topic Watch Topic
  • New Topic

Is java 8 getting difficult to read ?

 
salvin francis
Bartender
Posts: 1407
18
Eclipse IDE Google Web Toolkit Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Primarily, when learning method reference, I came across this :


If I read this right, first, I'll see there is a method call to Arrays.sort, with first parameter as the array itself and second parameter is something alien
Analyzing this, it's supposed to represent a lamba expression that simply calls a method with the same parameters (correct me if wrong)
so, i read it as "some interface with a method similar to

Now, since I know that Arrays.sort method's second method parameter is a Comparator, I start joining the dots and realize what it does.

All this is readable to me since I know :
  • Arrays.sort static method
  • String's compareToIgnoreCase method
  • Comparable interface

  • Now, what if I didn't know it ? (Sounds weird ? check the code below)

    Isn't this code less readable ? I would have to open the classes "Zoomer" and "Encast" to see what this method actually is

    Traditional coding would be like :

    I see a lot more info in the traditional way

    I hope I don't stir a huge controversy, I am here to learn too
     
    Stephan van Hulst
    Bartender
    Posts: 6583
    84
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    The code is unreadable because you used meaningless names like doSomething. Functional programming is all about describing what you're doing, not how. You can only describe the 'what' if you use meaningful names.

    I don't have to look at any documentation in any language to figure out what the line Arrays.sort(stringArray, String::compareToIgnoreCase); does. On the other hand, the following contains a lot more visual clutter:
     
    Stephan van Hulst
    Bartender
    Posts: 6583
    84
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    salvin francis wrote:All this is readable to me since I know :
  • Arrays.sort static method
  • String's compareToIgnoreCase method
  • Comparable interface


  • Even if you didn't know any of these, you could still guess the meaning of that one-liner, without looking at any documentation. That's the power of using functional programming where appropriate: things actually become easier to read.
     
    salvin francis
    Bartender
    Posts: 1407
    18
    Eclipse IDE Google Web Toolkit Java
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Stephan van Hulst wrote:
    Even if you didn't know any of these, you could still guess the meaning of that one-liner, without looking at any documentation. That's the power of using functional programming where appropriate: things actually become easier to read.

    It's a point of view about being easier to read. I do differ here. I agree I used meaningless names but the point here is that an entire Interface name is hidden here (Blooper). It just gets omitted in favor of compactness (or functional programming). While understanding a piece of code will be simpler if it was a part of java library classes and methods, will it be the same when referring to user classes and methods ?
     
    Stephan van Hulst
    Bartender
    Posts: 6583
    84
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    That has nothing to do with functional programming. You could achieve the same without lambdas and method references:


    By passing a method result you also hide the interface. Are methods bad? I contend that bad naming is bad.

     
    Stephan van Hulst
    Bartender
    Posts: 6583
    84
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Here are two pieces of code that print European countries.


    You might like the first approach better, but it hides the fact that it's using Predicates and Consumers through language constructs like the if-statement and the for-loop.

    Let's hide them in the functional code as well:

    So if we can hide Predicate and Consumer through language constructs (whether they're procedural statements or lambdas), then why not Country? Because it's a user type? That seems an arbitrary distinction.
     
    salvin francis
    Bartender
    Posts: 1407
    18
    Eclipse IDE Google Web Toolkit Java
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Stephan van Hulst wrote:

    Now this is getting interesting... is it the case that you are running 2 loops in the above case as opposed to 1 loop with an if condition in the traditional format ?
    Although your code looks concise, it seems that it first makes a smaller array only containing Europe and then iterates through the smaller array and prints each element

    Can your construct be simplified to something like :
     
    Campbell Ritchie
    Marshal
    Posts: 52580
    119
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    salvin francis wrote:. . . ... is it the case that you are running 2 loops in the above case as opposed to 1 loop with an if condition in the traditional format ?
    Although your code looks concise, it seems that it first makes a smaller array only containing Europe and then iterates through the smaller array and prints each element
    . . .
    You are not creating any loops; the Stream does all the iteration for you. It also runs in lazy execution so the first Stream only executes as many instances as are required by the second Stream. You probably execute forEach on the elements from filter (filter returns a stream object) immediately they are available, so the second stream probably operates inside the iteration from the first stream.
    Yes, you can use forEach without filter, but that does not simplify things. You ought to prune the Streams with filter first. There is no point in trying the functional features and then going back to the if‑else construct. That looks to me like reverting to a procedural style whereas streams combine functional programming with object orientation; a Stream is after all an object.
     
    Stephan van Hulst
    Bartender
    Posts: 6583
    84
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    A Stream is really a pipeline of operations. Only on a terminal operation such as forEach(), reduce() or collect() does it start iterating the source collection, and even then, it only takes the elements it needs. If I hadn't used the forEach(), nothing would have happened. Think of a Stream as a collection of objects that may or may not exist yet, and can be calculated for you on the fly as you need them.

    This is called 'lazy evaluation'. If you're interested in this, you should definitely take a look at the Haskell programming language, which gave me an amazing new perspective on writing software.
     
    salvin francis
    Bartender
    Posts: 1407
    18
    Eclipse IDE Google Web Toolkit Java
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Thanks for clarifying Campbell and Stephan.
    I am still trying to grasp the new language constructs. Hopefully am able to understand them all

    Having said that... it still looks a bit alien to me
    I have to also accept that a couple of years ago, generics and annotations too seemed weird to me and here I am using them all the time
     
    Rob Spoor
    Sheriff
    Posts: 20820
    68
    Chrome Eclipse IDE Java Windows
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Just for reference, there is no need to use String::compareToIgnoreCase for a Comparator. String.CASE_INSENSITIVE_ORDER has existed since Java 1.2.
     
    Jason Bullers
    Ranch Hand
    Posts: 111
    8
    Clojure IntelliJ IDE Java
    • Likes 2
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    salvin francis wrote:
    Now this is getting interesting... is it the case that you are running 2 loops in the above case as opposed to 1 loop with an if condition in the traditional format ?
    Although your code looks concise, it seems that it first makes a smaller array only containing Europe and then iterates through the smaller array and prints each element


    I feel like this is where you are going a little wrong with all the new functional tools added in Java 8: you're getting to hung up on the detailed how of all the new code and not looking at the abstraction as a whole. Granted, it's important to understand how all this stuff works as you are learning it (if you want a deep understanding of it all), but you shouldn't be thinking through all of that detail when you're reading the code. which is what some of your questions made me think you are doing. You should be focusing on what's being done in a declarative sense.

    In that last example, what's being done is simple and very readable (IMO at least): given a collection of countries, filter the ones in Europe and print them. The fact that you've raised the level of abstraction is important; the details of how to do all that are left to the stream and can be optimized six ways to Sunday without any impact on your code. You asked if there multiple loops (the answer is no), but does it matter? If it reads better and communicates your intent better, that's a win for developer productivity. If you profile it and prove it's slow (it most likely won't be), then investigate how to optimize it. As I mentioned earlier, one beautiful part of all this is that you get optimizations for free if streams get improved.
     
    salvin francis
    Bartender
    Posts: 1407
    18
    Eclipse IDE Google Web Toolkit Java
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Thanks for the info Jason Bullers, I am looking out into streams and attempting to learn them.
     
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!