Reputation: 188
I was going through the exercises in Java 8 in Action and I came across this question. There are 2 classes Trader and Transaction described as follows:
public class Trader {
private final String name;
private final String city;
public Trader(String n, String c) {
this.name = n;
this.city = c;
}
public String getName() {
return this.name;
}
public String getCity() {
return this.city;
}
public String toString() {
return "Trader:" + this.name + " in " + this.city;
}
}
public class Transaction {
private final Trader trader;
private final int year;
private final int value;
public Transaction(Trader trader, int year, int value) {
this.trader = trader;
this.year = year;
this.value = value;
}
public Trader getTrader() {
return this.trader;
}
public int getYear() {
return this.year;
}
public int getValue() {
return this.value;
}
public String toString() {
return "{" + this.trader + ", " + "year: " + this.year + ", " + "value:" + this.value + "}";
}
}
Traders and a list of transactions are created as follows:
Trader mario = new Trader("Mario", "Milan");
Trader alan = new Trader("Alan", "Cambridge");
Trader brian = new Trader("Brian", "Cambridge");
Trader raoul = new Trader("Raoul", "Cambridge");
List<Transaction> transactions = Arrays.asList(new Transaction(brian, 2011, 300),
new Transaction(raoul, 2012, 1000), new Transaction(raoul, 2011, 400),
new Transaction(mario, 2012, 710), new Transaction(mario, 2012, 700), new Transaction(alan, 2012, 950));
The question is to find all traders from Cambridge and sort them by name. The solution given to this problem in the book is as follows:
List<Trader> traders = transactions.stream()
.map(Transaction::getTrader)
.filter(trader -> trader.getCity().equals("Cambridge"))
.distinct()
.sorted(comparing(Trader::getName))
.collect(toList());
The answer provided above returns the correct results but I was wondering how and why is distinct() using the name field to return distinct traders?
Upvotes: 0
Views: 143
Reputation: 393906
distinct()
is not using name field to return distinct traders. It uses the equals
method to determine if two Trader
s are identical. Since Trader
doesn't override equals
, the only reason this code appears to work is that it passes the same instance (referenced by raoul
) to two Transaction
s, so the default equals
implementations (which checks ==
) is sufficient to determine that they are identical.
Hence the output List
is:
[Trader:Alan in Cambridge, Trader:Brian in Cambridge, Trader:Raoul in Cambridge]
However, if you make the following change:
Trader mario = new Trader("Mario", "Milan");
Trader alan = new Trader("Alan", "Cambridge");
Trader brian = new Trader("Brian", "Cambridge");
Trader raoul = new Trader("Raoul", "Cambridge");
Trader raoul2 = new Trader("Raoul", "Cambridge");
List<Transaction> transactions = Arrays.asList(new Transaction(brian, 2011, 300),
new Transaction(raoul, 2012, 1000), new Transaction(raoul2, 2011, 400),
new Transaction(mario, 2012, 710), new Transaction(mario, 2012, 700), new Transaction(alan, 2012, 950));
You'll see that now, since raoul
and raoul2
are not equal (even though they have the same name), they will both appear in the output List
:
[Trader:Alan in Cambridge, Trader:Brian in Cambridge, Trader:Raoul in Cambridge, Trader:Raoul in Cambridge]
Upvotes: 4
Reputation: 11
Stream.distinct() compare objects by Object.equals(Object) https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#distinct--
in this example, you have 4 Trader objects which are compared by the default implementation of Object.equals() since Trades class doesn't override equals method
Upvotes: 1