• Post Reply Bookmark Topic Watch Topic
  • New Topic

Weird Java syntax - Who can explain it?  RSS feed

 
Biniman Idugboe
Ranch Hand
Posts: 42
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
People of Java nation,
I am a brand new newbie in Java programming.  I have recently been reading introductory books and practicing Java codes.  A few days ago, I came upon fancy description "Lambda expressions".  I tried to read up a document titled "State of the Lambda".  I could hardly understand anything in it.  It is fair to say that it made me cry; thinking I am probably never going to be grounded in Java programming.  I see things like Comparator<Person> byName = Comparator.comparing(p -> p.getName());

I downloaded Java-8u131-docs-all and looked up Comparator.HTML.  I see things like static <T,U> Comparator<T> comparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator).  The associated description isn't that more friendly than the skill level required to understand the State of the Lambda document.   It feels sort of frustrating.  Please people, can anyone break the above syntax down to a friendly level for a newbie to understand?  Nice if you could also point to sources of materials that can help in understanding these kind of syntax.  
 
Ivan Jozsef Balazs
Rancher
Posts: 999
5
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I do not know that very document, but you might want to pick up some introduction to the lambda stuff.
Which is however not the most appropriate topic to begin Java with.
You might want first to learn the thing up to 1.7 and then turn to the lambda stuff.
 
Stephan van Hulst
Saloon Keeper
Posts: 7992
143
  • Likes 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, it is difficult, but with some practice you will get it. For now, let me explain to you the comparing() method.

Let's say we write a Country class, and Country has a capital() method that returns a City. Country doesn't implement Comparable because there is no natural way to compare two countries. Neither does City.

Now, we want to sort a list of countries by population count of their capital city:

You can easily construct such a Comparator using the comparing() method. You just need to tell it what property of the objects you want to sort them by. This is what the keyExtractor parameter is for:

This sorts a list of countries by taking the capital of each country, and comparing those instead. There's a problem with this approach though. Because a City can not be compared to another City naturally, we have to tell the comparing method how to compare two cities to each other. This is what the keyComparator parameter is for:

This says: "When comparing two countries, first take the capital city of both, and then take the population count of those capitals, and then compare the population counts to each other to find out how two countries should be compared".
Now that you know what these parameters mean, lets look at their types:

capitalExtractor is a function that transforms a Country to a City. populationCountExtractor is a function that transforms a City to an int. byPopulationCount is a comparator that compares two City objects. byPopulationCountOfCapital is a comparator that compares two Country objects.

So, you now know that int this case the comparing() method takes a Function<Country, City> and a Comparator<City>, and returns a Comparator<Country>. Let's take a look at how that matches with the method signature:

  • Function<? super T, ? extends U> is substituted by Function<Country, City>
  • Comparator<? super U> is substituted by Comparator<City>
  • Comparator<T> is substituted by Comparator<Country>

  • From this we can deduct that the type parameter T is substituted by Country, and type parameter U is substituted by City.

    Now, how do you figure out what types to pass when you want to write your own snippet of code? Work the other way around. First read from the documentation what the type parameters stand for, then then substitute your own types. Let's say you want to sort a list of cars by the power of their engine:

    What's the type of byEnginePower? You want to sort a list of Car, so that would be Comparator<Car>. Let's take a look at what type arguments we need to build something like that using the comparing() method.
    Type Parameters:
    T - the type of element to be compared
    U - the type of the Comparable sort key

    We want to sort a list of Car, so T is Car. The property of the Car you want to sort them by is the Engine. That means that after substitution, the method signature becomes comparing(Function<? super Car, ? extends Engine> keyExtractor, Comparator<? super Engine> keyComparator).

    We can now clearly see that the method requires a function that turns a Car into an Engine, and a comparator that compares Engine objects.

    Because Engine is not naturally comparable (would we naturally compare it by engine power, or by engine displacement, or what other property), we need to explicitly tell how to compare two engines using the byPower comparator. To do this, we would use the comparing() method again to get a comparator that compares two engines by power, but since power() is an int and not a reference type, we use the comparingInt() method instead. Again, we look at the type parameters in the documentation and substitute our types for them:
    Type Parameters:
    T - the type of element to be compared

    After substitution, the method signature is comparingInt(ToIntFunction<? super Engine> keyExtractor).

    Now that we have all the lambda expressions that we need, we can remove the variables and just nest them in one statement:

    The next step may look a bit weird, and you can learn about the details later, but as a final touch we can replace lambda expressions with method references, so that the code becomes even more succinct:

    I hope this makes everything a little bit more clear. Remember, this really IS a hard subject, so even though it seems frustrating now, you just need a lot of practice especially with the subjects of Generics and Lambda expressions.
     
    Carey Brown
    Saloon Keeper
    Posts: 3328
    46
    Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Stephan van Hulst wrote:Yes, it is difficult, but with some practice you will get it. For now, let me explain to you the comparing() method.....

    While you've presented a good write up I think you've also demonstrated why newbies should stick with Java 7 at first.
     
    Stephan van Hulst
    Saloon Keeper
    Posts: 7992
    143
    • Likes 2
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Disagree. People are perfectly capable of learning functional concepts from the start. The fact that they learn about lambdas as something that's bolted on top of some "basic Java" language is exactly why many people struggle with them, just like how learning OO is much more difficult for people who have started out learning procedural languages.
     
    Biniman Idugboe
    Ranch Hand
    Posts: 42
    1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Wow!  I can only thank all that have responded so far.  In particular, I raise my hat for Stephan on three points:
    1.  The time it took to put the explanations together.
    2.  The explanations
    3.  The more realistic classes in the example.
    Goes to show that some people still care about people they do not even know and probably will never know.  I cannot say for now that I grasped all the things explained, but I am sure I will grasp them when I have read them over and over. I owe you respect while still wondering how long and what level of efforts it took for you to get to this height of understanding.
     
    Arco Brouwer
    Ranch Hand
    Posts: 44
    2
    IntelliJ IDE Java Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    @Stephan van Hulst: Great post! Didn't have to much time to read know, but bookmarked it and will come back if I dive more into lambda expressions!
     
    Pop Bogdan
    Greenhorn
    Posts: 3
    Java Linux Oracle
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Great post Stephan!
    I wish I would have read something like your post when I was fist struggling with stuff like this.
     
    Stephan van Hulst
    Saloon Keeper
    Posts: 7992
    143
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Thank you all for your kind words and the cows. I have a final note to make. To fully demonstrate the comparing() method with two parameters, we first got a property from the objects to compare, and then built a new comparator to compare those properties. In most applications, you would just immediately get the real property to compare by in the first lambda expression:

    The comparing() method that takes a function and a comparator is useful for when you want to compare a property in some non-standard way, and you already have a comparator lying around that does that, such as Comparator.reverseOrder().

    We sorted a list of teams by the statistics() property of the teams. TeamStatistics is naturally comparable (using the total amount of points a team has), but this would sort our list starting with the last ranked team. That's why we pass Comparator.reverseOrder() to the comparing() call.
     
    It is sorta covered in the JavaRanch Style Guide.
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!