Потоки Java8 - удаление дубликатов с помощью Stream Distinct

У меня есть поток, например:

Arrays.stream(new String[]{"matt", "jason", "michael"});

Я хотел бы удалить имена, начинающиеся с того же письма, чтобы осталось только одно имя (не имеет значения, какое), начиная с этой буквы.

Я пытаюсь понять, как работает метод distinct(). Я прочитал в документации, что он основан на методе "равно" объекта. Однако, когда я пытаюсь обернуть String, я замечаю, что метод equals никогда не вызывается и ничего не удаляется. Здесь что-то не хватает?

Класс Wrapper:

static class Wrp {
    String test;
    Wrp(String s){
        this.test = s;
    }
    @Override
    public boolean equals(Object other){
        return this.test.charAt(0) == ((Wrp) other).test.charAt(0);
    }
}

И некоторый простой код:

public static void main(String[] args) {
    Arrays.stream(new String[]{"matt", "jason", "michael"})
    .map(Wrp::new)
    .distinct()
    .map(wrp -> wrp.test)
    .forEach(System.out::println);
}

Ответы

Ответ 1

Всякий раз, когда вы переопределяете equals, вам также необходимо переопределить метод hashCode(), который будет использоваться в реализации distinct().

В этом случае вы можете просто использовать

@Override public int hashCode() {
   return test.charAt(0);
}

..., который будет работать нормально.

Ответ 2

Альтернативный подход

    String[] array = {"matt", "jason", "michael"};
    Arrays.stream(array)
            .map(name-> name.charAt(0))
            .distinct()
            .map(ch -> Arrays.stream(array).filter(name->name.charAt(0) == ch).findAny().get())
            .forEach(System.out::println);