1

First of all, I am very new to Java 8, maybe my question won't apply to it at all...
So, I have a class that has a package private int and a String field. I have got to compare the instances by score and then by name. The solution is a class that must implement Comparator, and I'd like to solve it in Java 8, as I would code something like this, without the required class:

Arrays.sort(players, Comparator.comparing(Player.score).thenComparing(Player.name);

(players is an array of Player)
Is it possible at all? Overridden compare method should return an int, and I couldn't even get to a compiling code :( I tried this first:

public class Sorter implements Comparator<Player> {
    @Override
    public int compare(Player o1, Player o2) {
        return (int)(p1, p2) -> Comparator.comparing(Player.score).thenComparing(Player.name);
    }
}

It fails at Player.score and Player.name, because "Non-static reference score cannot be referenced from a static context" I don't understand how would this be a static context.
Then I created getter methods for score and name temporarily (it must remain without getters), and the problem turned into "int is not a functional interface".
I'd really appreciate if someone can tell if it is possible at all, and if so, drive me to the correct solution.
Thank you very much!

Edit: my question is not a duplicate of the how to use static variables question, because I wanted to know if my task is OK to solve in Java 8 and if yes, how. Having a Comparator as a field in my class, seems to solve this question (if getters were reachable).

monami
  • 594
  • 2
  • 9
  • 32
  • 1
    You need to provide `Function`s to `comparing` and `thenComparing`. Try `Comparator.comparing(player->player.score).thenComparing(player->player.name)` – Hank D May 29 '16 at 15:18
  • 2
    `compare` should return an `int` not a `Comparator`. If `Sorter` had the `Comparator` with the lambda expression as a static final field, your `compare` function could call its `compare` function. – Hank D May 29 '16 at 15:24
  • Thanks, @HankD ! That works perfectly, if I add getters for the fields temporarily. Since I cannot change the given circumstances, `public class Sorter implements Comparator { private static final Comparator comp = Comparator.comparing(Player.score).thenComparing(Player.name); @Override public int compare(Player o1, Player o2) { return comp.compare(o1, o2); } }` still has the problem with non-static field .. cannot be referenced..., etc. I tried something like this in .comparing: p -> ((Player)p).score, but still no result...Do you have more ideas? – monami May 29 '16 at 18:01
  • 1
    Can you make new classes with the same package name as Player? Other classes in the same package have visibility to package private members. Can you edit Player? Can you create a subclass that adds accessors? – Hank D May 29 '16 at 22:04
  • No for each questions :( It seems the task with these limits are for good old Java and not lambdas. Anyway, you provided the solution with the Comparator field in the Sorter class (works perfectly ig getters are there), so thank you! – monami Jun 02 '16 at 21:15

1 Answers1

1

There are a few problems here:

  1. You really should have getters rather than refer to public fields in the Player object. (I changed that in my example)
  2. Person::getScore is a method reference that will call the get score method later.
  3. You don't need a comparator implementation class. The idea is to use lambdas to replace the need for that.

The following working example shows what to do:

import java.util.*;

public class PlayTest {

    static class Player {
        private int score;
        private String name;
        public int getScore() {
            return score;
        }
        public void setScore(int score) {
            this.score = score;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return name;
        }
    }


    public static void main(String[] args) {
        Player p1 = new Player();
        p1.setScore(100);
        p1.setName("test 2");
        Player p2 = new Player();
        p2.setScore(100);
        p2.setName("test 1");

        List<Player> list= new ArrayList<>();
        list.add(p1);
        list.add(p2);

        Comparator<Player> comparator = Comparator.comparing(Player::getScore).thenComparing(Player::getName);

        Collections.sort(list, comparator);

        System.out.println(list);
    }
}
Jeanne Boyarsky
  • 12,156
  • 2
  • 49
  • 59
  • Thanks for doing this, but unfortunately the conditions I wrote are given, (no getters for fields, usage of Arrays.sort(), new class that implements Comparator), I cannot change them. Otherwise I would have solved the question the way as you did ;) – monami May 29 '16 at 17:42
  • 1
    Ah. So this is homework. If you need a new class that implements Comparator, I think the intent of the homework is that you not use lambdas. – Jeanne Boyarsky May 29 '16 at 20:00
  • Nope, it's a challenge. And yes, you may be right, I was just wondering if it makes sense to solve it with lambdas, that's why I asked for ideas. @Hank D almost has the answer :) – monami May 29 '16 at 20:28