91. Using LVTI to break up nested/large chains of expressions

Large/nested expressions are usually snippets of codes that look pretty impressive and are intimidating. They are commonly seen as pieces of smart or clever code. It is controversial as to whether this is good or bad, but most likely, the balance tends to be in favor of those who claim that such code should be avoided. For example, check out the following expression:

List<Integer> ints = List.of(1, 1, 2, 3, 4, 4, 6, 2, 1, 5, 4, 5);

// Avoid
int result = ints.stream()
.collect(Collectors.partitioningBy(i -> i % 2 == 0))
.values()
.stream()
.max(Comparator.comparing(List::size))
.orElse(Collections.emptyList())
.stream()
.mapToInt(Integer::intValue)
.sum();

Such expressions can be written deliberately or they can represent the final result of an incremental process that enriches an initially small expression in time. Nevertheless, when such expressions start to become gaps in readability, they must be broken into pieces via local variables. But this is not fun and can be considered exhausting work that we want to avoid:

List<Integer> ints = List.of(1, 1, 2, 3, 4, 4, 6, 2, 1, 5, 4, 5);

// Prefer
Collection<List<Integer>> evenAndOdd = ints.stream()
.collect(Collectors.partitioningBy(i -> i % 2 == 0))
.values();

List<Integer> evenOrOdd = evenAndOdd.stream()
.max(Comparator.comparing(List::size))
.orElse(Collections.emptyList());

int sumEvenOrOdd = evenOrOdd.stream()
.mapToInt(Integer::intValue)
.sum();

Check out the types of the local variables in the preceding code. We have Collection<List<Integer>>, List<Integer>, and int. It is obvious that these explicit types require some time to be fetched and written. This may be a good reason to avoid breaking this expression into pieces. Nevertheless, the triviality of using the var type instead of explicit types is tempting if we wish to adopt the local variable's style because it saves time that's usually spent fetching the explicit types:

var intList = List.of(1, 1, 2, 3, 4, 4, 6, 2, 1, 5, 4, 5);

// Prefer
var evenAndOdd = intList.stream()
.collect(Collectors.partitioningBy(i -> i % 2 == 0))
.values();

var evenOrOdd = evenAndOdd.stream()
.max(Comparator.comparing(List::size))
.orElse(Collections.emptyList());

var sumEvenOrOdd = evenOrOdd.stream()
.mapToInt(Integer::intValue)
.sum();

Awesome! Now, it is the compiler's job to infer the types of these local variables. We only choose the points where we break the expression and demarcate them with var.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset