EnumSet.complementOf returns a new set containing enum constants absent from the supplied EnumSet. Its universe is the entire enum type, not just constants known to one caller.
Java EnumSet complementOf: derive a default-deny capability set
Operational contract
The helper constructs a fresh denied set from an allowed capability set. Adding a new enum constant automatically puts it in denied until the policy explicitly allows it, which is appropriate for this default-deny design. The result is a separate mutable EnumSet; changing allowed later does not update the previous result. If a product instead interprets the complement as granted permissions, a newly introduced constant could become granted accidentally. The allowed set itself still requires an authorization source and review.
Failure case
A release adds ARCHIVE. Existing callers allow only READ and EXPORT. The computed denied set includes ARCHIVE without changing the callers' allowlists.
Java code
import java.util.EnumSet;
import java.util.Objects;
public class ReceiptCapabilityPolicy {
public enum Capability { READ, EXPORT, DELETE, ARCHIVE }
public static EnumSet<Capability> denied(EnumSet<Capability> allowed) {
Objects.requireNonNull(allowed);
return EnumSet.complementOf(allowed);
}
}Performance and ownership cost
Complement construction visits the enum universe and copies a compact bit representation, taking O(E) work in the number of enum constants under a portable cost model and O(E) result bits. The policy computation is small but should not replace explicit authorization checks at the action boundary.
Common Mistakes
- Do not use a complement as granted permissions without reviewing new enum constants.
- Do not assume the returned set is a live view of allowed.
- Do not treat enum membership alone as proof that a caller is authorized.
Connected lessons
- Java EnumMap: declaration order and nullable values
- Java EnumSet: retain element type when a source collection is empty
- Java collection factories: rejected updates and shallow element ownership
- Java BitSet: distinguish logical length, capacity, and set-bit count
- Java BitSet nextSetBit: scan a bounded index range without walking gaps
- Java NavigableSet subSet: account for a live backed range
- Java specialized collections quiz
- Advanced Java
