Ich möchte gern Listen mit Hilfe von mehreren Prädikaten filtern. Meine Anforderungen dabei:
Das ist super. Ich kann Listen mit Threads und Comments gleichermaßen filtern.
Allerdings möchte ich Listen nach verschiedenen Prädikaten filtern. (Die auskommentierten Stellen ergänzen ein weiteres Attribut zum Filtern). Ich bekomme meine filter-Methode jedoch nicht dazu verschiedene Prädikate zu akzeptieren. Es ist logisch, da die Liste momentan an <T extends HasAuthorName> Elemente gebunden ist. Ich komme leider nicht weiter, wie ich das erreichen kann.
Ich habe das Projekt in den Anhang gepackt, falls jemand probieren möchte.
- die Funktion zum Filtern ist gleich für Listen verschiedener Typen (bspw. gleich für List<Thread> und List<Comment>)
- die Prädikate sind anwendbar auf mehrere Typen (durch Implementierung des Interfaces HasXXX)
- die Typen der Prädikate, die zum Filtern in die Methode gesteckt werden werden von den Elementen des Liste implementiert.
Java:
public interface HasAuthorName {
String getAuthorName();
}
public interface HasApprovedStatus {
boolean isApproved();
}
public class Thread implements HasAuthorName
//, HasApprovedStatus
{
private final Author author;
private final boolean isApproved;
public Thread(Author author, boolean isApproved) {
this.author = author;
this.isApproved = isApproved;
}
@Override
public String getAuthorName() {
return author.getName();
}
// @Override
public boolean isApproved() {
return isApproved;
}
}
public class Comment implements HasAuthorName {
private final Author author;
public Comment(Author author) {
this.author = author;
}
@Override
public String getAuthorName() {
return author.getName();
}
}
public abstract class Filter {
private Filter() {}
public static <T extends HasAuthorName> List<T> filter(List<T> list, Predicate<HasAuthorName>... predicates) {
return list.stream()
.filter(Arrays.stream(predicates).reduce($ -> true, Predicate::and))
.collect(Collectors.toList());
}
}
Java:
class FilterTest {
private static List<Thread> threads;
private static List<Comment> comments;
private Predicate<HasAuthorName> authorNameLongerThan4CharsPredicate = o -> o.getAuthorName().length() > 4;
//private Predicate<HasApprovedStatus> approvedStatusPredicate = HasApprovedStatus::isApproved;
@BeforeAll
static void setUp() {
final Author a1 = new Author("Lisa");
final Author a2 = new Author("Theo");
final Author a3 = new Author("Alfred");
comments = Collections.unmodifiableList(Lists.list(
new Comment(a1),
new Comment(a2),
new Comment(a3)
));
threads = Collections.unmodifiableList(Lists.list(
new Thread(a1, true),
new Thread(a1, false)
));
}
@Test
void testNamePredicate() {
assertThat(authorNameLongerThan4CharsPredicate.test(() -> "a")).isFalse();
assertThat(authorNameLongerThan4CharsPredicate.test(() -> "abcd")).isFalse();
assertThat(authorNameLongerThan4CharsPredicate.test(() -> "abcde")).isTrue();
}
//@Test
//void testApprovedPredicate() {
// assertThat(approvedStatusPredicate.test(new Thread(new Author(""), true))).isTrue();
// assertThat(approvedStatusPredicate.test(new Thread(new Author(""), false))).isFalse();
//}
@Test
void filterAuthorNames() {
assertThat(Filter.filter(comments, authorNameLongerThan4CharsPredicate)).hasSize(1);
assertThat(Filter.filter(threads, authorNameLongerThan4CharsPredicate)).hasSize(0);
}
//@Test
//void filterCombined() {
// assertThat(Filter.filter(comments, authorNameLongerThan4CharsPredicate)).hasSize(1);
// assertThat(Filter.filter(threads, authorNameLongerThan4CharsPredicate, approvedStatusPredicate)).hasSize(0);
//}
}
Ich habe das Projekt in den Anhang gepackt, falls jemand probieren möchte.