Search code examples
javajava-14java-record

Is this snippet compiling? I don't think so Java 14 records


The weekend I was reading some about Java 14 preview feature records. I didn't want to make this question because seems to be a code for Brian Goetz, and we all know who this guy is and what represents to the Java ecosystem, but this was kicking in my head since and I know it will be learning for me.

The link is here. https://www.infoq.com/articles/java-14-feature-spotlight/?utm_campaign=infoq_content&utm_source=infoq&utm_medium=feed&utm_term=Java

Is something like this.

record PlayerScore(Player player, Score score) {
    // convenience constructor for use by Stream::map
    PlayerScore(Player player) { this(player, getScore(player)); }
}

List<Player> topN
    = players.stream()
             .map(PlayerScore::new)
             .sorted(Comparator.comparingInt(PlayerScore::score))
             .limit(N)
             .map(PlayerScore::player)
             .collect(toList());

I assume that this line is returning a Score reference.

getScore(player)

Perhaps you have see it before I understand what it tries to do but there is something I don't understand. Maybe I'm wrong.

This line

.sorted(Comparator.comparingInt(PlayerScore::score))

The API for comparingInt is like this.

public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {

But as long as I understand the method reference

PlayerScore::score

Is returning a Score reference from the Records tuple right? is not a Integer or resulting in a Integer

Or this would make the code compile I think perhaps is a typing error.

record PlayerScore(Player player, int score) {
    // convenience constructor for use by Stream::map
    PlayerScore(Player player) { this(player, getScore(player)); }
}

On my understanding this code would not compile, as I stated before; maybe I'm wrong.


Solution

  • The reason why this might not compile could be because Score is a type and not an Integer value. What you would need to do for comparing the Score of record PlayerScore is to ensure two things -

    1. Use Comparator.comparing while

      List<Player> topN  = players.stream()
           .map(PlayerScore::new)
           .sorted(Comparator.comparing(PlayerScore::score)) //here
           .limit(N)
           .map(PlayerScore::player)
           .collect(toList());
      
    2. Make sure Score implements Comparable such as :

      class Score implements Comparable<Score> {
          @Override
          public int compareTo(Score o) {
              return 0; // implementation
          }
      }
      

    Sadly, I don't see an implementation of your Score class in the linked document either, which is where it's crucial to understand what exactly has the author(or editor) missed there. For example, a simple record definition change would make the existing code work :

    record PlayerScore(Player player, Integer score) { 
        // convenience constructor for use by Stream::map
        PlayerScore(Player player) {
            this(player, getScore(player));
        }
    }
    
    List<Player> topN = players.stream()
            .map(PlayerScore::new)
            .sorted(Comparator.comparingInt(PlayerScore::score))
            .limit(N)
            .map(PlayerScore::player)
            .collect(Collectors.toList());
    

    Just a glance at that section, since it's in continuity with the previous example, what matters to correlate is the return type of getScore(Player player).

    // notice the signature change
    static int getScore(Player player) {
        return 0;
    }