If I got your idea correctly - here is my answer inspired by [this answer][1]:
class Data {
Integer id;
String name;
public Data(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
@Override
public String toString() {
return "Data{" + "id=" + id + ", name='" + name + '\'' + '}';
}
}
public class Main {
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
public static void main(String[] args) {
List<Data> list = List.of(new Data(1, "abc.jpg"), new Data(2, "bcd.png"), new Data(1, null));
List<Data> result = list.stream()
.filter(d -> d.name != null && !d.name.equals(""))
.filter(distinctByKey(Data::getId))
.collect(Collectors.toList());
result.forEach(System.out::println);
}
}
[1]: https://stackoverflow.com/questions/23699371/java-8-distinct-by-property
Consider `distinct` to be a *stateful filter*. Here is a function that returns a predicate that maintains state about what it's seen previously, and that returns whether the given element was seen for the first time:
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
Then you can write:
persons.stream().filter(distinctByKey(Person::getName))
Note that if the stream is ordered and is run in parallel, this will preserve an *arbitrary* element from among the duplicates, instead of the first one, as `distinct()` does.
(This is essentially the same as [my answer][1] to this question: https://stackoverflow.com/questions/27870136/java-lambda-stream-distinct-on-arbitrary-key)
[1]: https://stackoverflow.com/a/27872086/1441122