{"id":23902859,"url":"https://github.com/mtumilowicz/java11-covariance-contravariance-invariance","last_synced_at":"2026-02-26T02:04:57.778Z","repository":{"id":110876864,"uuid":"158696754","full_name":"mtumilowicz/java11-covariance-contravariance-invariance","owner":"mtumilowicz","description":"Covariance, invariance, contravariance overview of collections in Java 11, vavr, guava.","archived":false,"fork":false,"pushed_at":"2025-05-05T19:23:47.000Z","size":75,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-06-03T14:14:10.533Z","etag":null,"topics":["collection","contravariance","covariance","guava","invariance","vavr"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mtumilowicz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-11-22T12:34:04.000Z","updated_at":"2025-05-05T19:23:50.000Z","dependencies_parsed_at":"2025-05-27T02:09:39.031Z","dependency_job_id":"c7f1dca7-b9f1-43d8-ab5d-616157138268","html_url":"https://github.com/mtumilowicz/java11-covariance-contravariance-invariance","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mtumilowicz/java11-covariance-contravariance-invariance","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fjava11-covariance-contravariance-invariance","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fjava11-covariance-contravariance-invariance/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fjava11-covariance-contravariance-invariance/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fjava11-covariance-contravariance-invariance/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mtumilowicz","download_url":"https://codeload.github.com/mtumilowicz/java11-covariance-contravariance-invariance/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fjava11-covariance-contravariance-invariance/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261768807,"owners_count":23207079,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["collection","contravariance","covariance","guava","invariance","vavr"],"created_at":"2025-01-04T22:50:55.533Z","updated_at":"2026-02-26T02:04:52.754Z","avatar_url":"https://github.com/mtumilowicz.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.com/mtumilowicz/java11-covariance-contravariance-invariance.svg?branch=master)](https://travis-ci.com/mtumilowicz/java11-covariance-contravariance-invariance)\n\n# java11-covariance-contravariance-invariance\nCovariance, invariance, contravariance overview of collections in Java 11, vavr, guava.\n\n_Reference_: https://dzone.com/articles/covariance-and-contravariance  \n_Reference_: https://docs.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance  \n_Reference_: https://medium.freecodecamp.org/understanding-java-generic-types-covariance-and-contravariance-88f4c19763d2  \n\n# preface\n## formal\n* **Covariance** - enables you to use a more derived type than \noriginally specified.\n    \u003e If A is a subtype of B then X[A] should be a subtype \n    of X[B].\n* **Contravariance** - enables you to use a more generic \n(less derived) type than originally specified.\n    \u003e If A is a supertype of B then X[A] should be a \n    supertype of X[B].\n* **Invariance** - means that you can use only the type \noriginally specified; so an invariant generic type \nparameter is neither covariant nor contravariant.\n\n## java\nVariance refers to how subtyping between more complex \ntypes relates to subtyping between their components.\n\n**Generics in Java are invariant.** (Java has no way \nof knowing at runtime the type information of the \ntype parameters, due to type erasure)\n\n* Covariance: accept subtypes\n    \u003e Arrays in java are covariant.\n* Contravariance: accept supertypes\n    \u003e No easy examples in java (unless wildcards).\n* Invariance: neither covariant nor contravariant\n    \u003e Generics are invarant\n\nWith wildcards, it’s possible for generics to support \ncovariance and contravariance.\n\n* Covariance: `? extends Integer`\n    ```\n    List\u003cInteger\u003e ints = new LinkedList\u003c\u003e();\n    List\u003c? extends Number\u003e nums = ints;\n    ```\n* Contravariance: `? super Integer`\n    ```\n    List\u003cInteger\u003e ints = new LinkedList\u003c\u003e();\n    List\u003c? super Integer\u003e nums = ints;\n    ```\n* Remark:\n    * covariance is read-only\n    * contravariance is write-only\n    * otherwise compile-time error\n\n**Covariance could be dangerous** (`JavaUtilCollectionsTest`):\n```\nDog[] dogs = new Dog[5];\nAnimal[] animals = dogs;\n\nanimals[0] = new Cat(); // ArrayStoreException\n```\n\n**Mutability combined with covariance would break type safety:**\n```\nList\u003cString\u003e strs = new ArrayList\u003cString\u003e();\nList\u003cObject\u003e objs = strs; // !!! The cause of the upcoming problem sits here. Java prohibits this!\nobjs.add(1); // Here we put an Integer into a list of Strings\nString s = strs.get(0); // !!! ClassCastException: Cannot cast Integer to String\n```\n\n**Note that covariance can't be dangerous with \nimmutable / readonly collections, cause we can't\nmodify them.**\n\n## use case\n1. suppose we have method that we cannot modify\n    ```\n    static void process(List\u003cAnimal\u003e animals) {\n        ...\n    }\n    ```\n1. then we cannot invoke (because of compile time error)\n    ```\n    process(new LinkedList\u003cDog\u003e()) // compile time error\n    ```\n1. but we could try to bypass it with a trick\n    ```\n    process(Collections.unmodifiableList(new LinkedList\u003cDog\u003e()))\n    ```\n\n# project description\n* we have hierarchical structure:\n    * `interface Animal extends Comparable\u003cAnimal\u003e`\n    * `class Cat implements Animal`\n    * `class Dog implements Animal`\n    * `class BigDog extends Dog`\n    \n* what we can't do?\n    ```\n    List\u003cDog\u003e dogs = new LinkedList\u003c\u003e();\n    List\u003cAnimal\u003e animals = dogs; // compile time error\n    ```\n    \n* what we can do?\n    * using vavr:\n        ```\n        HashSet\u003cDog\u003e dogs = HashSet.of(new Dog(), new Dog());\n        HashSet\u003cAnimal\u003e animals = HashSet.ofAll(dogs);\n        HashSet\u003cAnimal\u003e animals2 = HashSet.narrow(dogs);\n        \n        HashSet\u003cAnimal\u003e animals3 = HashSet.of(new Dog(), new Dog());\n        ```\n        * `HashSet\u003cT\u003e ofAll(java.lang.Iterable\u003c? extends T\u003e elements)`\n        * `HashSet\u003cT\u003e narrow(io.vavr.collection.HashSet\u003c? extends T\u003e hashSet)`\n        * in `VavrCollectionsTest` tests for: `HashSet`, `List`, \n        `TreeSet`, `HashMap`\n    * using guava\n        ```\n        ImmutableSet\u003cDog\u003e dogs = ImmutableSet.of(new Dog(), new Dog());\n        ImmutableSet\u003cAnimal\u003e animals = ImmutableSet.of(new Dog(), new Dog());\n        ImmutableSet\u003cAnimal\u003e animals2 = ImmutableSet.copyOf(Collections.\u003cDog\u003eemptySet());\n        ```\n        * `ImmutableSet\u003cE\u003e copyOf(Collection\u003c? extends E\u003e elements)`\n        * in `GuavaCollectionsTest` tests for: `ImmutableSet`, \n        `ImmutableList`, `ImmutableSortedSet`, `ImmutableMap`\n    * pure java\n        * factory methods\n            ```\n            List\u003cDog\u003e dogs = List.of(new Dog(), new Dog());\n            List\u003cAnimal\u003e animals = List.of(new Dog(), new Dog());\n            List\u003cAnimal\u003e animals2 = List.copyOf(dogs);\n            ```\n        * `Collections.unmodifiableXXX`\n            ```\n            List\u003cDog\u003e dogs = new LinkedList\u003c\u003e();\n            dogs.add(new Dog());\n            \n            List\u003cAnimal\u003e dogsAsAnimals = Collections.unmodifiableList(dogs);\n            ```\n        * in `JavaUtilCollectionsTest` tests for: \n        `List`, `Collections.unmodifiableList`, \n        `Set`, `Collections.unmodifiableSet`,\n        `Map`, `Collections.unmodifiableMap`,\n        `Collections.unmodifiableNavigableSet`,\n        `Collections.unmodifiableSortedSet`,\n        `Collections.unmodifiableCollection`\n        \n    * note that you could also use wildcards:\n        * Please refer my other github project for PECS principle:\n          https://github.com/mtumilowicz/java11-pecs-principle\n        * covariance, read-only\n            ```\n            Dog dog = new Dog();\n            \n            List\u003cDog\u003e dogs = new LinkedList\u003c\u003e();\n            dogs.add(dog);\n            \n            List\u003c? extends Animal\u003e animals = dogs;\n            //        animals.add(new Cat()); compile time error even as Cat extends Animal\n            //        animals.add(new Dog()); compile time error even as Dog extends Animal - we are not sure if animals are dogs only\n            \n            Animal getDog = dogsAsAnimal.get(0);\n    \n            assertThat(getDog, is(dog));\n            ```\n        * contravariance, write-only\n            ```\n            List\u003cDog\u003e dogs = new LinkedList\u003c\u003e();\n    \n            List\u003c? super Dog\u003e onlyDogSpecies = dogs;\n            onlyDogSpecies.add(new Dog());\n            onlyDogSpecies.add(new BigDog());\n            // onlyDogSpecies.add(new Object()); compile time error\n            // explanation: List\u003c? super Dog\u003e can be List\u003cDog\u003e, List\u003cAnimal\u003e, or even List\u003cObject\u003e =\u003e no adding, because we don't know what real type is there\n    \n            //        Animal getDog = dogsAsAnimal.get(0); compile time error - List\u003c? super Dog\u003e might be List\u003cDog\u003e, List\u003cAnimal\u003e, or even List\u003cObject\u003e\n    \n            assertThat(onlyDogSpecies.size(), is(2));\n            ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fjava11-covariance-contravariance-invariance","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmtumilowicz%2Fjava11-covariance-contravariance-invariance","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fjava11-covariance-contravariance-invariance/lists"}