{"id":"generics-interfaces","slug":"generic-interfaces","title":"Generic interfaces","text":"An interface can have a type parameter too. You've used one since module 38:\n\n```java\npublic interface Comparable<T> {\n    int compareTo(T other);\n}\n```\n\nA Talk class implemented it as `Comparable<Talk>`, so its `compareTo` took a Talk. Java's `List<E>`, `Map<K, V>` and `Iterator<E>` from modules 35 and 39 are generic interfaces as well.\n\n### A generic interface of your own\n\nA comic convention's ticket form checks what people type. The name to print on the entry pass must be long enough, the T-shirt size must be S, M or L, and the number of tickets must be 1, 2 or 4. Every check takes a value and answers yes or no; only the type of the value differs. One interface describes them all:\n\n```java\npublic interface Rule<T> {\n    boolean allows(T value);\n}\n```\n\nA class can implement a generic interface in two ways: for one type that it chooses, or for any type, by keeping the type parameter.\n\n### Implemented for one type\n\n```java\npublic class MinLength implements Rule<String> {\n    private int min;\n\n    public MinLength(int min) {\n        this.min = min;\n    }\n\n    @Override\n    public boolean allows(String value) {\n        return value.length() >= this.min;\n    }\n}\n```\n\n`implements Rule<String>` chooses String for T, exactly like `implements Comparable<Talk>`. So MinLength's `allows` takes a String, and it can call `length()` on it. MinLength has no type parameter of its own: it's a Rule for Strings only.\n\n### Kept generic\n\n```java\nimport java.util.ArrayList;\n\npublic class OneOf<T> implements Rule<T> {\n    private ArrayList<T> allowed;\n\n    public OneOf() {\n        this.allowed = new ArrayList<>();\n    }\n\n    public void add(T value) {\n        this.allowed.add(value);\n    }\n\n    @Override\n    public boolean allows(T value) {\n        return this.allowed.contains(value);\n    }\n}\n```\n\n`OneOf<T> implements Rule<T>` has a type parameter of its own, and it hands it on to the interface. A `OneOf<String>` is a `Rule<String>`, and a `OneOf<Integer>` is a `Rule<Integer>`. OneOf works for any type because all it does with a value is `contains`, which compares with `equals`, and every object has an `equals`.\n\n### Using them\n\nA `Rule<String>` can be a variable's type or a parameter's type, like any interface (module 35), and it accepts any class that is a Rule for Strings:\n\n```java\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        Rule<String> passName = new MinLength(4);\n        OneOf<String> sizes = new OneOf<>();\n        sizes.add(\"S\");\n        sizes.add(\"M\");\n        sizes.add(\"L\");\n        OneOf<Integer> tickets = new OneOf<>();\n        tickets.add(1);\n        tickets.add(2);\n        tickets.add(4);\n\n        System.out.println(passName.allows(\"Ari\") + \" \" + passName.allows(\"Arianna\"));\n        System.out.println(tickets.allows(3) + \" \" + tickets.allows(4));\n\n        ArrayList<String> typed = new ArrayList<>();\n        typed.add(\"M\");\n        typed.add(\"XL\");\n        typed.add(\"m\");\n        typed.add(\"L\");\n        System.out.println(countAllowed(sizes, typed) + \" of \" + typed.size() + \" are sizes\");\n        System.out.println(countAllowed(passName, typed) + \" of \" + typed.size() + \" are long enough for a pass\");\n    }\n\n    public static int countAllowed(Rule<String> rule, ArrayList<String> values) {\n        int count = 0;\n        for (String value : values) {\n            if (rule.allows(value)) {\n                count++;\n            }\n        }\n        return count;\n    }\n}\n// ==== Rule.java ====\npublic interface Rule<T> {\n    boolean allows(T value);\n}\n// ==== MinLength.java ====\npublic class MinLength implements Rule<String> {\n    private int min;\n\n    public MinLength(int min) {\n        this.min = min;\n    }\n\n    @Override\n    public boolean allows(String value) {\n        return value.length() >= this.min;\n    }\n}\n// ==== OneOf.java ====\nimport java.util.ArrayList;\n\npublic class OneOf<T> implements Rule<T> {\n    private ArrayList<T> allowed;\n\n    public OneOf() {\n        this.allowed = new ArrayList<>();\n    }\n\n    public void add(T value) {\n        this.allowed.add(value);\n    }\n\n    @Override\n    public boolean allows(T value) {\n        return this.allowed.contains(value);\n    }\n}\n```\n\n```output\nfalse true\nfalse true\n2 of 4 are sizes\n0 of 4 are long enough for a pass\n```\n\n- `countAllowed` takes any `Rule<String>`: a OneOf of Strings and a MinLength both fit. Each object runs its own `allows`.\n- `tickets`, a `Rule<Integer>`, doesn't fit: `countAllowed(tickets, typed)` doesn't compile, because a rule for numbers can't check text. Step 5 shows more of what the compiler checks.\n- `\"m\"` isn't a size: `contains` uses String's `equals`, which tells small letters from capitals.\n","task":"The form also asks for the buyer's age, which must be from 13 to 120. `Rule.java` is ready. In `Between.java`, write the class `Between`, which implements `Rule<Integer>`. Its constructor `Between(int min, int max)` takes the smallest and the largest value allowed, and `allows` allows a value from `min` to `max`, both included. The check runs:\n\n```java\nRule<Integer> age = new Between(13, 120);\nSystem.out.println(age.allows(12) + \" \" + age.allows(13) + \" \" + age.allows(120) + \" \" + age.allows(121));\n```\n\nand expects:\n\n```\nfalse true true false\n```\n","kind":"code","seed":"// ==== Between.java ====\npublic class Between {\n\n}\n\n// ==== Rule.java ====\npublic interface Rule<T> {\n    boolean allows(T value);\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Rule<Integer> age = new Between(13, 120);\n        System.out.println(age.allows(12) + \" \" + age.allows(13) + \" \" + age.allows(120) + \" \" + age.allows(121));\n    }\n}\n","solution":"// ==== Between.java ====\npublic class Between implements Rule<Integer> {\n    private int min;\n    private int max;\n\n    public Between(int min, int max) {\n        this.min = min;\n        this.max = max;\n    }\n\n    @Override\n    public boolean allows(Integer value) {\n        return value >= this.min && value <= this.max;\n    }\n}\n\n// ==== Rule.java ====\npublic interface Rule<T> {\n    boolean allows(T value);\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Rule<Integer> age = new Between(13, 120);\n        System.out.println(age.allows(12) + \" \" + age.allows(13) + \" \" + age.allows(120) + \" \" + age.allows(121));\n    }\n}\n","hints":["The header is `public class Between implements Rule<Integer>`. Keep `min` and `max` in two int instance variables.","With T chosen as Integer, the method to write is `public boolean allows(Integer value)`, with `@Override` above it. `allows(int value)` wouldn't do: its parameter type isn't the interface's. The body is `return value >= this.min && value <= this.max;`."],"tests":[{"name":"Test 1","stdin":"","call":"Rule<Integer> age = new Between(13, 120);\nSystem.out.println(age.allows(12) + \" \" + age.allows(13) + \" \" + age.allows(120) + \" \" + age.allows(121));\n","expect":"false true true false","hidden":false},{"name":"Test 2","stdin":"","call":"Between floors = new Between(-2, 9);\nSystem.out.println(floors.allows(-3) + \" \" + floors.allows(-2) + \" \" + floors.allows(0) + \" \" + floors.allows(9) + \" \" + floors.allows(10));\nRule<Integer> exact = new Between(7, 7);\nSystem.out.println(exact.allows(6) + \" \" + exact.allows(7) + \" \" + exact.allows(8));\n","expect":"false true true true false\nfalse true false","hidden":true}],"require":[{"pattern":"\\bclass\\s+Between\\s+implements\\s+Rule\\s*<\\s*Integer\\s*>","message":"Write the header as `public class Between implements Rule<Integer>`."}],"forbid":[],"more":[{"task":"A shoe shop's app checks the sizes in stock and the names on its gift cards. `Rule`, `MinLength` and `OneOf` are this step's. Look at when 42 is added. What does this program print?\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        OneOf<Integer> inStock = new OneOf<>();\n        inStock.add(38);\n        inStock.add(40);\n        Rule<Integer> sizes = inStock;\n        inStock.add(42);\n        System.out.println(sizes.allows(42) + \" \" + sizes.allows(39));\n\n        Rule<String> name = new MinLength(3);\n        String[] names = {\"Al\", \"Bea\", \"Christopher\", \"\"};\n        int count = 0;\n        for (String n : names) {\n            if (name.allows(n)) {\n                count++;\n            }\n        }\n        System.out.println(count);\n    }\n}\n// ==== Rule.java ====\npublic interface Rule<T> {\n    boolean allows(T value);\n}\n// ==== MinLength.java ====\npublic class MinLength implements Rule<String> {\n    private int min;\n\n    public MinLength(int min) {\n        this.min = min;\n    }\n\n    @Override\n    public boolean allows(String value) {\n        return value.length() >= this.min;\n    }\n}\n// ==== OneOf.java ====\nimport java.util.ArrayList;\n\npublic class OneOf<T> implements Rule<T> {\n    private ArrayList<T> allowed;\n\n    public OneOf() {\n        this.allowed = new ArrayList<>();\n    }\n\n    public void add(T value) {\n        this.allowed.add(value);\n    }\n\n    @Override\n    public boolean allows(T value) {\n        return this.allowed.contains(value);\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        OneOf<Integer> inStock = new OneOf<>();\n        inStock.add(38);\n        inStock.add(40);\n        Rule<Integer> sizes = inStock;\n        inStock.add(42);\n        System.out.println(sizes.allows(42) + \" \" + sizes.allows(39));\n\n        Rule<String> name = new MinLength(3);\n        String[] names = {\"Al\", \"Bea\", \"Christopher\", \"\"};\n        int count = 0;\n        for (String n : names) {\n            if (name.allows(n)) {\n                count++;\n            }\n        }\n        System.out.println(count);\n    }\n}\n// ==== Rule.java ====\npublic interface Rule<T> {\n    boolean allows(T value);\n}\n// ==== MinLength.java ====\npublic class MinLength implements Rule<String> {\n    private int min;\n\n    public MinLength(int min) {\n        this.min = min;\n    }\n\n    @Override\n    public boolean allows(String value) {\n        return value.length() >= this.min;\n    }\n}\n// ==== OneOf.java ====\nimport java.util.ArrayList;\n\npublic class OneOf<T> implements Rule<T> {\n    private ArrayList<T> allowed;\n\n    public OneOf() {\n        this.allowed = new ArrayList<>();\n    }\n\n    public void add(T value) {\n        this.allowed.add(value);\n    }\n\n    @Override\n    public boolean allows(T value) {\n        return this.allowed.contains(value);\n    }\n}\n","hints":["`Rule<Integer> sizes = inStock;` doesn't copy anything: `sizes` and `inStock` refer to the same OneOf object, so the 42 added afterwards is in it too.","MinLength(3) allows Strings of 3 characters or more: Bea and Christopher. Al has 2, and the empty String has 0."],"tests":[{"name":"Output","stdin":"","expect":"true false\n2","hidden":false}],"require":[],"forbid":[],"lines":["true false","2"]},{"task":"To change an order, a person types its booking reference, which must pass several rules at once. `Rule.java`, `MinLength.java`, `NoSpaces.java` and `Between.java` are ready. In `AllOf.java`, write the class `AllOf<T>`, which implements `Rule<T>` and stays generic. It keeps its rules in an `ArrayList<Rule<T>>` (a `List<Rule<T>>` variable that holds an ArrayList is fine too), and has:\n\n- a constructor `AllOf()`, which starts with no rules\n- `add(Rule<T> rule)`, which adds a rule\n- `allows(T value)`, which allows a value only when every rule in the list allows it. With no rules, it allows everything.\n\nThe check runs:\n\n```java\nAllOf<String> reference = new AllOf<>();\nreference.add(new MinLength(4));\nreference.add(new NoSpaces());\nSystem.out.println(reference.allows(\"K7Q\") + \" \" + reference.allows(\"K7Q 22X\") + \" \" + reference.allows(\"K7Q22X\"));\nAllOf<Integer> pin = new AllOf<>();\nSystem.out.println(pin.allows(7));\npin.add(new Between(1000, 9999));\nSystem.out.println(pin.allows(7) + \" \" + pin.allows(2468));\n```\n\nand expects:\n\n```\nfalse false true\ntrue\nfalse true\n```\n","kind":"code","seed":"// ==== AllOf.java ====\nimport java.util.ArrayList;\n\npublic class AllOf {\n\n}\n\n// ==== Rule.java ====\npublic interface Rule<T> {\n    boolean allows(T value);\n}\n\n// ==== MinLength.java ====\npublic class MinLength implements Rule<String> {\n    private int min;\n\n    public MinLength(int min) {\n        this.min = min;\n    }\n\n    @Override\n    public boolean allows(String value) {\n        return value.length() >= this.min;\n    }\n}\n\n// ==== NoSpaces.java ====\npublic class NoSpaces implements Rule<String> {\n    @Override\n    public boolean allows(String value) {\n        return !value.contains(\" \");\n    }\n}\n\n// ==== Between.java ====\npublic class Between implements Rule<Integer> {\n    private int min;\n    private int max;\n\n    public Between(int min, int max) {\n        this.min = min;\n        this.max = max;\n    }\n\n    @Override\n    public boolean allows(Integer value) {\n        return value >= this.min && value <= this.max;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        AllOf<String> reference = new AllOf<>();\n        reference.add(new MinLength(4));\n        reference.add(new NoSpaces());\n        System.out.println(reference.allows(\"K7Q\") + \" \" + reference.allows(\"K7Q 22X\") + \" \" + reference.allows(\"K7Q22X\"));\n        AllOf<Integer> pin = new AllOf<>();\n        System.out.println(pin.allows(7));\n        pin.add(new Between(1000, 9999));\n        System.out.println(pin.allows(7) + \" \" + pin.allows(2468));\n    }\n}\n","solution":"// ==== AllOf.java ====\nimport java.util.ArrayList;\n\npublic class AllOf<T> implements Rule<T> {\n    private ArrayList<Rule<T>> rules;\n\n    public AllOf() {\n        this.rules = new ArrayList<>();\n    }\n\n    public void add(Rule<T> rule) {\n        this.rules.add(rule);\n    }\n\n    @Override\n    public boolean allows(T value) {\n        for (Rule<T> rule : this.rules) {\n            if (!rule.allows(value)) {\n                return false;\n            }\n        }\n        return true;\n    }\n}\n\n// ==== Rule.java ====\npublic interface Rule<T> {\n    boolean allows(T value);\n}\n\n// ==== MinLength.java ====\npublic class MinLength implements Rule<String> {\n    private int min;\n\n    public MinLength(int min) {\n        this.min = min;\n    }\n\n    @Override\n    public boolean allows(String value) {\n        return value.length() >= this.min;\n    }\n}\n\n// ==== NoSpaces.java ====\npublic class NoSpaces implements Rule<String> {\n    @Override\n    public boolean allows(String value) {\n        return !value.contains(\" \");\n    }\n}\n\n// ==== Between.java ====\npublic class Between implements Rule<Integer> {\n    private int min;\n    private int max;\n\n    public Between(int min, int max) {\n        this.min = min;\n        this.max = max;\n    }\n\n    @Override\n    public boolean allows(Integer value) {\n        return value >= this.min && value <= this.max;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        AllOf<String> reference = new AllOf<>();\n        reference.add(new MinLength(4));\n        reference.add(new NoSpaces());\n        System.out.println(reference.allows(\"K7Q\") + \" \" + reference.allows(\"K7Q 22X\") + \" \" + reference.allows(\"K7Q22X\"));\n        AllOf<Integer> pin = new AllOf<>();\n        System.out.println(pin.allows(7));\n        pin.add(new Between(1000, 9999));\n        System.out.println(pin.allows(7) + \" \" + pin.allows(2468));\n    }\n}\n","hints":["The header is `public class AllOf<T> implements Rule<T>`, like OneOf's. The instance variable is `private ArrayList<Rule<T>> rules;`, and `add` takes a `Rule<T>`.","`allows` goes through the rules with `for (Rule<T> rule : this.rules)`, and returns `false` as soon as one rule doesn't allow the value. After the loop, every rule has allowed it, so it returns `true`, which is also the answer when there are no rules."],"tests":[{"name":"Test 1","stdin":"","call":"AllOf<String> reference = new AllOf<>();\nreference.add(new MinLength(4));\nreference.add(new NoSpaces());\nSystem.out.println(reference.allows(\"K7Q\") + \" \" + reference.allows(\"K7Q 22X\") + \" \" + reference.allows(\"K7Q22X\"));\nAllOf<Integer> pin = new AllOf<>();\nSystem.out.println(pin.allows(7));\npin.add(new Between(1000, 9999));\nSystem.out.println(pin.allows(7) + \" \" + pin.allows(2468));\n","expect":"false false true\ntrue\nfalse true","hidden":false},{"name":"Test 2","stdin":"","call":"AllOf<Integer> age = new AllOf<>();\nage.add(new Between(0, 120));\nage.add(new Between(18, 200));\nSystem.out.println(age.allows(17) + \" \" + age.allows(18) + \" \" + age.allows(120) + \" \" + age.allows(121));\nRule<String> title = new AllOf<>();\nSystem.out.println(title.allows(\"\") + \" \" + title.allows(\"any text at all\"));\nAllOf<String> code = new AllOf<>();\ncode.add(new NoSpaces());\ncode.add(new MinLength(2));\ncode.add(new MinLength(6));\nSystem.out.println(code.allows(\"abc\") + \" \" + code.allows(\"abcdef\") + \" \" + code.allows(\"abc def\"));\n","expect":"false true true false\ntrue true\nfalse true false","hidden":true}],"require":[{"pattern":"\\bclass\\s+AllOf\\s*<\\s*(\\w+)\\s*>\\s+implements\\s+Rule\\s*<\\s*\\1\\s*>","message":"Write the header as `public class AllOf<T> implements Rule<T>`, so that AllOf stays generic."},{"pattern":"\\b(?:Array)?List\\s*<\\s*Rule\\s*<\\s*\\w+\\s*>\\s*>","message":"Keep the rules in an `ArrayList<Rule<T>>`, or in a `List<Rule<T>>` that holds one."}],"forbid":[]}]}