An open API service indexing awesome lists of open source software.

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.

Awesome Lists containing this project

README

          

[![Build Status](https://travis-ci.com/mtumilowicz/java11-covariance-contravariance-invariance.svg?branch=master)](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));
```