https://github.com/mtumilowicz/java11-covariance-contravariance-invariance
Covariance, invariance, contravariance overview of collections in Java 11, vavr, guava.
https://github.com/mtumilowicz/java11-covariance-contravariance-invariance
collection contravariance covariance guava invariance vavr
Last synced: 5 months ago
JSON representation
Covariance, invariance, contravariance overview of collections in Java 11, vavr, guava.
- Host: GitHub
- URL: https://github.com/mtumilowicz/java11-covariance-contravariance-invariance
- Owner: mtumilowicz
- Created: 2018-11-22T12:34:04.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2025-05-05T19:23:47.000Z (about 1 year ago)
- Last Synced: 2025-06-03T14:14:10.533Z (about 1 year ago)
- Topics: collection, contravariance, covariance, guava, invariance, vavr
- Language: Java
- Homepage:
- Size: 73.2 KB
- Stars: 2
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
[](https://travis-ci.com/mtumilowicz/java11-covariance-contravariance-invariance)
# java11-covariance-contravariance-invariance
Covariance, invariance, contravariance overview of collections in Java 11, vavr, guava.
_Reference_: https://dzone.com/articles/covariance-and-contravariance
_Reference_: https://docs.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance
_Reference_: https://medium.freecodecamp.org/understanding-java-generic-types-covariance-and-contravariance-88f4c19763d2
# preface
## formal
* **Covariance** - enables you to use a more derived type than
originally specified.
> If A is a subtype of B then X[A] should be a subtype
of X[B].
* **Contravariance** - enables you to use a more generic
(less derived) type than originally specified.
> If A is a supertype of B then X[A] should be a
supertype of X[B].
* **Invariance** - means that you can use only the type
originally specified; so an invariant generic type
parameter is neither covariant nor contravariant.
## java
Variance refers to how subtyping between more complex
types relates to subtyping between their components.
**Generics in Java are invariant.** (Java has no way
of knowing at runtime the type information of the
type parameters, due to type erasure)
* Covariance: accept subtypes
> Arrays in java are covariant.
* Contravariance: accept supertypes
> No easy examples in java (unless wildcards).
* Invariance: neither covariant nor contravariant
> Generics are invarant
With wildcards, it’s possible for generics to support
covariance and contravariance.
* Covariance: `? extends Integer`
```
List ints = new LinkedList<>();
List extends Number> nums = ints;
```
* Contravariance: `? super Integer`
```
List ints = new LinkedList<>();
List super Integer> nums = ints;
```
* Remark:
* covariance is read-only
* contravariance is write-only
* otherwise compile-time error
**Covariance could be dangerous** (`JavaUtilCollectionsTest`):
```
Dog[] dogs = new Dog[5];
Animal[] animals = dogs;
animals[0] = new Cat(); // ArrayStoreException
```
**Mutability combined with covariance would break type safety:**
```
List strs = new ArrayList();
List objs = strs; // !!! The cause of the upcoming problem sits here. Java prohibits this!
objs.add(1); // Here we put an Integer into a list of Strings
String s = strs.get(0); // !!! ClassCastException: Cannot cast Integer to String
```
**Note that covariance can't be dangerous with
immutable / readonly collections, cause we can't
modify them.**
## use case
1. suppose we have method that we cannot modify
```
static void process(List animals) {
...
}
```
1. then we cannot invoke (because of compile time error)
```
process(new LinkedList()) // compile time error
```
1. but we could try to bypass it with a trick
```
process(Collections.unmodifiableList(new LinkedList()))
```
# project description
* we have hierarchical structure:
* `interface Animal extends Comparable`
* `class Cat implements Animal`
* `class Dog implements Animal`
* `class BigDog extends Dog`
* what we can't do?
```
List dogs = new LinkedList<>();
List animals = dogs; // compile time error
```
* what we can do?
* using vavr:
```
HashSet dogs = HashSet.of(new Dog(), new Dog());
HashSet animals = HashSet.ofAll(dogs);
HashSet animals2 = HashSet.narrow(dogs);
HashSet animals3 = HashSet.of(new Dog(), new Dog());
```
* `HashSet ofAll(java.lang.Iterable extends T> elements)`
* `HashSet narrow(io.vavr.collection.HashSet extends T> hashSet)`
* in `VavrCollectionsTest` tests for: `HashSet`, `List`,
`TreeSet`, `HashMap`
* using guava
```
ImmutableSet dogs = ImmutableSet.of(new Dog(), new Dog());
ImmutableSet animals = ImmutableSet.of(new Dog(), new Dog());
ImmutableSet animals2 = ImmutableSet.copyOf(Collections.emptySet());
```
* `ImmutableSet copyOf(Collection extends E> elements)`
* in `GuavaCollectionsTest` tests for: `ImmutableSet`,
`ImmutableList`, `ImmutableSortedSet`, `ImmutableMap`
* pure java
* factory methods
```
List dogs = List.of(new Dog(), new Dog());
List animals = List.of(new Dog(), new Dog());
List animals2 = List.copyOf(dogs);
```
* `Collections.unmodifiableXXX`
```
List dogs = new LinkedList<>();
dogs.add(new Dog());
List dogsAsAnimals = Collections.unmodifiableList(dogs);
```
* in `JavaUtilCollectionsTest` tests for:
`List`, `Collections.unmodifiableList`,
`Set`, `Collections.unmodifiableSet`,
`Map`, `Collections.unmodifiableMap`,
`Collections.unmodifiableNavigableSet`,
`Collections.unmodifiableSortedSet`,
`Collections.unmodifiableCollection`
* note that you could also use wildcards:
* Please refer my other github project for PECS principle:
https://github.com/mtumilowicz/java11-pecs-principle
* covariance, read-only
```
Dog dog = new Dog();
List dogs = new LinkedList<>();
dogs.add(dog);
List extends Animal> animals = dogs;
// animals.add(new Cat()); compile time error even as Cat extends Animal
// animals.add(new Dog()); compile time error even as Dog extends Animal - we are not sure if animals are dogs only
Animal getDog = dogsAsAnimal.get(0);
assertThat(getDog, is(dog));
```
* contravariance, write-only
```
List dogs = new LinkedList<>();
List super Dog> onlyDogSpecies = dogs;
onlyDogSpecies.add(new Dog());
onlyDogSpecies.add(new BigDog());
// onlyDogSpecies.add(new Object()); compile time error
// explanation: List super Dog> can be List, List, or even List => no adding, because we don't know what real type is there
// Animal getDog = dogsAsAnimal.get(0); compile time error - List super Dog> might be List, List, or even List
assertThat(onlyDogSpecies.size(), is(2));
```