Note: this is for practicing functional style programming, not for actual use.
I've created a Set implementation which uses Java Predicates to check if an object exists in the set or not. Adding an object is handled by creating a new Predicate (to check if the incoming object is equal to the newly added one), and OR-ing it with the previous predicates.
I have finished implementing and testing the basic features: contains, add, remove, intersect, setMinus, union.
However, I'm stuck on how to implement any iterator related functions, e.g. so that the user can use a for each loop.
Is there any functional way to do this? (i.e. avoiding Collections or arrays)
Here is what I have so far. I've also created some unit tests here.
import java.util.Collection; import java.util.function.Predicate; public class PredicateSet<E> { private Predicate<E> rootPredicate = e -> false; private int size = 0; public int size() { return size; } public boolean isEmpty() { return size == 0; } public boolean contains(Object o) { try { return rootPredicate.test((E) o); } catch (ClassCastException cce) { return false; } } public boolean add(E e) { if (contains(e)) return false; Predicate<E> newPredicate = e::equals; rootPredicate = newPredicate.or(rootPredicate); size++; return true; } public boolean remove(Object o) { try { if (!contains(o)) return false; } catch (ClassCastException cce) { return false; } E e = (E) o; Predicate<E> newPredicate = e::equals; rootPredicate = newPredicate.negate().and(rootPredicate); size--; return true; } public boolean containsAll(Collection<? extends E> c) { return c.stream().allMatch(this::contains); } public boolean addAll(Collection<? extends E> c) { var changed = false; for (E e : c) { if (add(e)) changed = true; } return changed; } public boolean removeAll(Collection<? extends E> c) { var changed = false; for (E e : c) { if (remove(e)) changed = true; } return changed; } public boolean intersect(Collection<? extends E> c) { PredicateSet<E> intersection = new PredicateSet<>(); for (var x : c) { try { if (contains(x)) intersection.add(x); } catch (ClassCastException ignored) { } } var changed = this.size != intersection.size; this.rootPredicate = intersection.rootPredicate; this.size = intersection.size; return changed; } public boolean setMinus(Collection<? extends E> c) { var changed = false; for (var x : c) { try { if (remove(x)) changed = true; } catch (ClassCastException ignored) { } } return changed; } public boolean union(Collection<? extends E> c) { var changed = false; for (var x : c) { try { if (add(x)) changed = true; } catch (ClassCastException ignored) { } } return changed; } public void clear() { this.size = 0; rootPredicate = e -> false; } }