Java 8 Özelliğe göre ayırt etme

Java 8'de Stream API'sini kullanarak her nesnenin bir özelliğinin farklılığını kontrol ederek bir koleksiyonu nasıl filtreleyebilirim?

Örneğin, bir Person nesnesi listem var ve aynı ada sahip kişileri kaldırmak istiyorum,

persons.stream().distinct();

Bir Person nesnesi için varsayılan eşitlik kontrolünü kullanacak, bu yüzden şöyle bir şeye ihtiyacım var,

persons.stream().distinct(p -> p.getName());

Ne yazık ki distinct() yönteminin böyle bir aşırı yüklemesi yoktur. Person` sınıfı içindeki eşitlik kontrolünü değiştirmeden bunu kısa ve öz bir şekilde yapmak mümkün mü?

Bir alternatif de isimleri anahtar olarak kullanarak kişileri bir haritaya yerleştirmek olabilir:

persons.collect(toMap(Person::getName, p -> p, (p, q) -> p)).values();

Çift isim olması durumunda, tutulan Kişinin ilk bulunan kişi olacağını unutmayın.

Yorumlar (11)

Kişi nesnelerini, yalnızca kişilerin adlarını karşılaştıran başka bir sınıfa sarabilirsiniz. Daha sonra, tekrar bir kişi akışı elde etmek için sarılmış nesneleri açarsınız. Akış işlemleri aşağıdaki gibi görünebilir:

persons.stream()
    .map(Wrapper::new)
    .distinct()
    .map(Wrapper::unwrap)
    ...;

Wrapper` sınıfı aşağıdaki gibi görünebilir:

class Wrapper {
    private final Person person;
    public Wrapper(Person person) {
        this.person = person;
    }
    public Person unwrap() {
        return person;
    }
    public boolean equals(Object other) {
        if (other instanceof Wrapper) {
            return ((Wrapper) other).person.getName().equals(person.getName());
        } else {
            return false;
        }
    }
    public int hashCode() {
        return person.getName().hashCode();
    }
}
Yorumlar (6)

Bunu uygulamanın en kolay yolu, bir öğenin özelliği kullanılarak oluşturulabilen isteğe bağlı bir Comparator sağladığı için sıralama özelliğine atlamaktır. Daha sonra, sıralanmış bir akış için tüm eşit öğelerin bitişik olduğu gerçeğini kullanan durum dolu bir Predicate kullanılarak yapılabilecek kopyaları filtrelemeniz gerekir:

Comparator c=Comparator.comparing(Person::getName);
stream.sorted(c).filter(new Predicate() {
    Person previous;
    public boolean test(Person p) {
      if(previous!=null && c.compare(previous, p)==0)
        return false;
      previous=p;
      return true;
    }
})./* more stream operations here */;

Elbette, statefull bir Predicate iş parçacığı güvenli değildir, ancak ihtiyacınız buysa bu mantığı bir Collector içine taşıyabilir ve Collectorınızı kullanırken iş parçacığı güvenliğini akışın halletmesine izin verebilirsiniz. Bu, sorunuzda bize söylemediğiniz farklı öğelerin akışıyla ne yapmak istediğinize bağlıdır.

Yorumlar (0)