JCombiner is a framework to generate combinations of collections for Java. I have written it in Java 11 using Java 9 modules (JPMS) and Gradle as build tool. JUnit 5 and Mockito are used for unit testing and Jacoco for code coverage. Streams and the Collectors API are extensively used throughout the development of JCombiner project.

Some years ago I wrote junit-parameters, which is basically a custom JUnit test runner that make it possible to add parameters to JUnit 4 test methods.

Browsing its source code SonarLint pointed me a large conditional if/else method from the ParameterTypeConverterFactory class:

This method converts the method parameter to its specific type based on its Class object. As it is few lines long, it showed me a good opportunity to refactor this code a little bit with a more elegant solution. This project has unit tests, so I could start refactoring it in small steps and start over again whether I have made a mistake.

This was the first change of breaking this complicated conditional method into a more readable one. It was safe to do so because after each change I could run my unit tests suite to assert I haven’t broken anything. The next refactoring could be towards a more object-oriented approach like Replace Conditional with Polymorphism.

What did you think about this refactoring? Have you ever had such a situation? Drop your comments here!

Some days ago I was developing a task on a Gradle project and I faced with a situation where I had to convert a Map < String, List < String >> to List < Pair >, each pair containing the key and one element from the List.

I decided to compare the solution in three different languages: Java 8 (using lambdas and the Streams API), Groovy and Ruby to see how concise and expressive they would be. Then, I created the Groovy code and it looked like this:

The Groovy and Ruby version are very expressive and concise. Note the use of the collectMany method on the Groovy version and the use of the flatten method on the Ruby version to flatten the result list into a single list of pairs.
The Java 8 version made use of the collect method of the Stream API, to collect the results in a list of Pair instances, each one holding the key and value of each element from the List< String >.

There are some unit tests to validate the solution. I’ve found it a good opportunity to exercise the use of lambdas so I decided to solve it. Below is my solution to this kata.

The first method should take the String list and sort all the String elements in ascending (ASCII) order:

Java

1

2

3

4

5

6

7

8

9

10

11

/**

* This method should take the String List and sort all the String elements in ascending (ASCII) order.

*

* @return The sorted values in ascending ASCII order.

*/

publicList<String>getSortedStrings(){

returnvalues

.stream()

.sorted()

.collect(Collectors.toList());

}

The other method should take the String list and:

filter the elements that contains one or more digits

transform (map) the remaining Strings into Integers

sort the Integers in ascending order

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

/**

* This method should take the String List and:

* <ol>

* <li>filter the elements that contains one or more digits;</li>

* <li>transform (map) the remaining Strings into Integers;</li>

* <li>sort the Integers in ascending order.</li>

* </ol>

*

* @return

*/

publicList<Integer>getSortedIntegers(){

returnvalues

.stream()

.filter(s->s.matches("\\d+"))

.map(Integer::valueOf)

.sorted()

.collect(Collectors.toList());

}

The last method should take the String list and:

filter the elements that contains one or more digits

transform (map) the remaining Strings into Integers

sort the Integers in descending order

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

/**

* This method should take the String List and:

* <ol>

* <li>filter the elements that contains one or more digits;</li>

* <li>transform (map) the remaining Strings into Integers;</li>

* <li>sort the Integers in descending order.</li>

* </ol>

*

* @return

*/

publicList<Integer>getSortedDescendingIntegers(){

returnvalues

.stream()

.filter(s->s.matches("\\d+"))

.map(Integer::valueOf)

.sorted(Comparator.reverseOrder())

.collect(Collectors.toList());

}

Note that the steps filter the elements that contains one or more digits and transform (map) the remaining Strings into Integers are identical. So I decided to extract the partial Stream into a method with the Extract Method refactoring support on IntelliJ IDEA:

Java

1

2

3

4

5

6

privateStream<Integer>integersWithOneOrMoreDigits(){

returnvalues

.stream()

.filter(s->s.matches("\\d+"))

.map(Integer::valueOf);

}

Then I refactored the the solution to use the new extracted method:

Java

1

2

3

4

5

publicList<Integer>getSortedIntegers(){

returnintegersWithOneOrMoreDigits()

.sorted()

.collect(Collectors.toList());

}

Java

1

2

3

4

5

publicList<Integer>getSortedDescendingIntegers(){

returnintegersWithOneOrMoreDigits()

.sorted(Comparator.reverseOrder())

.collect(Collectors.toList());

}

I re-run the tests and they all passed. What do you think about this solution? Do you suggest other ones?

You are currently browsing the archives for the lambdas category.

The opinions expressed here are entirely my own and do not necessarily reflect those of my employer.