├── .gitignore
├── img
└── solution.png
├── pom.xml
├── readme.md
└── src
├── main
└── java
│ └── com
│ └── github
│ └── hubertwo
│ └── kata
│ └── stream
│ └── Fruit.java
└── test
├── java
└── com
│ └── github
│ └── hubertwo
│ └── kata
│ └── stream
│ └── basics
│ ├── BasicsJava11Test.java
│ ├── BasicsTest.java
│ ├── FibonacciSequenceTest.java
│ └── PalindromeTest.java
└── resources
└── java11
└── fruitList.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | .idea
3 | *.iml
4 |
5 |
--------------------------------------------------------------------------------
/img/solution.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HubertWo/java-stream-kata/c020be62b6dc25eecf91abeee31c91bc1fcf8f0f/img/solution.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.github.hubertwo.kata.stream
8 | java-stream-kata
9 | 1.0-SNAPSHOT
10 |
11 |
12 | UTF-8
13 |
14 |
15 |
16 |
17 |
18 | org.apache.maven.plugins
19 | maven-compiler-plugin
20 | 3.8.1
21 |
22 | 11
23 | 11
24 |
25 |
26 |
27 | org.apache.maven.plugins
28 | maven-surefire-plugin
29 | 2.22.1
30 |
31 |
32 |
33 |
34 |
35 | org.junit.jupiter
36 | junit-jupiter-api
37 | 5.3.2
38 | test
39 |
40 |
41 | org.junit.jupiter
42 | junit-jupiter-engine
43 | 5.3.2
44 | test
45 |
46 |
47 | org.assertj
48 | assertj-core
49 | 3.12.2
50 | test
51 |
52 |
53 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Java Stream Kata
2 |
3 | > A code kata is an exercise in programming which helps programmers hone their skills through practice and repetition.
4 | > https://en.wikipedia.org/wiki/Kata_(programming)
5 |
6 | This repository contains different tasks related to Java Streams.
7 |
8 | ## Leave a :star: :)
9 | If you like the content do not forget to leave a star at the top right corner. Thank you!
10 |
11 | https://github.com/HubertWo/java-stream-kata
12 |
13 | ## Setup
14 | Minimal setup is required. Tools you will need:
15 | - Java 11+
16 | - Maven
17 | - IDE (In my case IntelliJ IDEA)
18 |
19 | ## How to run exercises
20 | Each exercise is an jUnit test.
21 | You can run test from both Maven or any modern IDE.
22 |
23 | ## Where are answers?
24 | Each task has solution in "Click here to see the answer" block.
25 |
26 |
27 | #### Branch with all answers
28 | Branch ```answers``` has all answers in place and all tests are green.
29 |
30 | ### Maven
31 | To check *task1* from *Basics* package:
32 | ```
33 | mvn surefire:test -Dtest=BasicsTest#task1
34 | ```
35 |
36 | ### IDE
37 | After importing project press "Play" near the test you want to run.
38 |
39 | ## More
40 | - Java Stream API: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/package-summary.html
41 | - How to run single test using Maven : https://maven.apache.org/surefire/maven-surefire-plugin/examples/single-test.html
42 | - How to run single test using IntelliJ IDEA: https://www.jetbrains.com/help/idea/performing-tests.html
43 |
--------------------------------------------------------------------------------
/src/main/java/com/github/hubertwo/kata/stream/Fruit.java:
--------------------------------------------------------------------------------
1 | package com.github.hubertwo.kata.stream;
2 |
3 | import java.util.Objects;
4 |
5 | /**
6 | * Fruit representation.
7 | *
8 | * @author https://github.com/HubertWo
9 | */
10 | public final class Fruit {
11 | private final String name;
12 | private final int calories;
13 |
14 | public Fruit(String name, int calories) {
15 | this.name = name;
16 | this.calories = calories;
17 | }
18 |
19 | public String getName() {
20 | return name;
21 | }
22 |
23 | public int getCalories() {
24 | return calories;
25 | }
26 |
27 | /**
28 | * Returning only name of fruit for readability.
29 | */
30 | @Override
31 | public String toString() {
32 | return getName();
33 | }
34 |
35 | @Override
36 | public boolean equals(Object o) {
37 | if (this == o) return true;
38 | if (o == null || getClass() != o.getClass()) return false;
39 | Fruit fruit = (Fruit) o;
40 | return calories == fruit.calories &&
41 | Objects.equals(name, fruit.name);
42 | }
43 |
44 | @Override
45 | public int hashCode() {
46 | return Objects.hash(name, calories);
47 | }
48 | }
--------------------------------------------------------------------------------
/src/test/java/com/github/hubertwo/kata/stream/basics/BasicsJava11Test.java:
--------------------------------------------------------------------------------
1 | package com.github.hubertwo.kata.stream.basics;
2 |
3 | import com.github.hubertwo.kata.stream.Fruit;
4 | import org.junit.jupiter.api.DisplayName;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import java.io.IOException;
8 | import java.net.URI;
9 | import java.net.URISyntaxException;
10 | import java.nio.file.Files;
11 | import java.nio.file.Paths;
12 | import java.util.List;
13 | import java.util.Set;
14 | import java.util.function.Predicate;
15 |
16 | import static java.util.stream.Collectors.toUnmodifiableList;
17 | import static org.assertj.core.api.Assertions.assertThat;
18 |
19 | /**
20 | * By doing this tasks you will learn how to use:
21 | *
22 | * - {@link Predicate#not}
23 | * - {@link String#lines}
24 | *
25 | *
26 | * @author https://github.com/HubertWo
27 | */
28 | @SuppressWarnings("SimplifyStreamApiCallChains")
29 | @DisplayName("Stream basics - Java 11")
30 | class BasicsJava11Test {
31 |
32 | private static final String LINE_SEPARATOR = System.getProperty("line.separator");
33 |
34 | private static final Fruit BANANA = new Fruit("Banana", 105);
35 | private static final Fruit PAPAYA = new Fruit("Papaya", 109);
36 | private static final Fruit KIWI = new Fruit("Kiwi", 46);
37 | private static final Fruit MANGO = new Fruit("Mango", 107);
38 | private static final Fruit PEACH = new Fruit("Peach", 48);
39 |
40 | private static final Set FRUITS = Set.of(PAPAYA, BANANA, KIWI, MANGO, PEACH);
41 |
42 | //
43 | /*
44 | FRUITS.stream()
45 | .filter(Predicate.not(f -> f.equals(BANANA)))
46 | .collect(toUnmodifiableList());
47 | */
48 | //
49 | @Test
50 | @DisplayName("Task: Get all fruits except BANANA")
51 | void task1() {
52 | final List everythingExceptBanana = FRUITS.stream()
53 | // TODO: put your answer here
54 | .collect(toUnmodifiableList());
55 |
56 | assertThat(everythingExceptBanana)
57 | .doesNotContain(BANANA)
58 | .containsExactlyInAnyOrder(PAPAYA, KIWI, MANGO, PEACH);
59 | }
60 |
61 | //
62 | /*
63 | givenFruitList
64 | .lines()
65 | .map(line -> line.split(","))
66 | .map(splittedLine -> new Fruit(splittedLine[0], Integer.parseInt(splittedLine[1])))
67 | .collect(toList());
68 | */
69 | //
70 | @Test
71 | @DisplayName("Task: Load fruit list from file")
72 | void task2() throws IOException, URISyntaxException {
73 | // Loads the String from resources file
74 | URI resource = ClassLoader.getSystemResource("java11/fruitList.txt").toURI();
75 | final String givenFruitList = Files.readString(Paths.get(resource));
76 |
77 | // TODO: convert givenFruitList to list using Streams
78 | final List actualFruitList = null;
79 |
80 | assertThat(actualFruitList)
81 | .containsExactlyInAnyOrderElementsOf(FRUITS);
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/src/test/java/com/github/hubertwo/kata/stream/basics/BasicsTest.java:
--------------------------------------------------------------------------------
1 | package com.github.hubertwo.kata.stream.basics;
2 |
3 | import com.github.hubertwo.kata.stream.Fruit;
4 | import org.junit.jupiter.api.DisplayName;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import java.util.*;
8 | import java.util.function.Function;
9 | import java.util.function.Supplier;
10 | import java.util.function.ToIntFunction;
11 | import java.util.stream.Collectors;
12 | import java.util.stream.Stream;
13 |
14 | import static java.util.stream.Collectors.toList;
15 | import static org.assertj.core.api.Assertions.assertThat;
16 |
17 | /**
18 | * By doing this tasks you will learn how to use:
19 | *
20 | * - {@link Stream#sorted}
21 | * - {@link Stream#limit(long)}
22 | * - {@link Stream#reduce}
23 | * - {@link Stream#mapToInt(ToIntFunction)}
24 | * - {@link Stream#flatMap(Function)}
25 | * - {@link Collectors#groupingBy(Function)}
26 | * - {@link Collectors#counting()}
27 | * - {@link Comparator#comparing(Function)}
28 | * - {@link Function#identity()}
29 | * - {@link Stream#generate(Supplier)}
30 | *
31 | *
32 | * @author https://github.com/HubertWo
33 | */
34 | @SuppressWarnings("SimplifyStreamApiCallChains")
35 | @DisplayName("Stream basics")
36 | class BasicsTest {
37 |
38 | private static final Fruit BANANA = new Fruit("Banana", 105);
39 | private static final Fruit PAPAYA = new Fruit("Papaya", 109);
40 | private static final Fruit KIWI = new Fruit("Kiwi", 46);
41 | private static final Fruit MANGO = new Fruit("Mango", 107);
42 | private static final Fruit PEACH = new Fruit("Peach", 48);
43 |
44 | private static final Set FRUITS = Set.of(PAPAYA, BANANA, KIWI, MANGO, PEACH);
45 |
46 | //
47 | /*
48 | .sorted(Comparator.comparing(Fruit::getCalories).reversed())
49 | .limit(2)
50 | .collect(toList());
51 | */
52 | //
53 | @Test
54 | @DisplayName("Task: Find 2 fruits with biggest amount of calories")
55 | void task1() {
56 | List mostCaloricFruits = FRUITS.stream().collect(toList()); // TODO: FRUITS.stream()
57 |
58 | assertThat(mostCaloricFruits).containsExactly(PAPAYA, MANGO);
59 | }
60 |
61 | //
62 | /*
63 | FRUITS.stream().mapToInt((Fruit fruit) -> fruit.getCalories() / 2).sum();
64 | */
65 | //
66 | @Test
67 | @DisplayName("Task: Take half of each fruit and get the sum of calories")
68 | void task2() {
69 | final int sumOfCalories = 0; // TODO: FRUITS.stream()
70 |
71 | assertThat(sumOfCalories).isEqualTo(206);
72 | }
73 |
74 | //
75 | /*
76 | FRUITS.stream()
77 | .collect(Collectors
78 | .groupingBy((Fruit fruit) -> fruit.getName().charAt(0), Collectors.toSet()
79 | )
80 | ));
81 | */
82 | //
83 | @Test
84 | @DisplayName("Task: Group fruits by first letter")
85 | void task3() {
86 | final Map> mapOfFruits = Collections.emptyMap(); // TODO: FRUITS.stream()
87 |
88 | assertThat(mapOfFruits.keySet()).contains('B', 'K', 'M', 'P');
89 | assertThat(mapOfFruits.get('B')).hasSize(1);
90 | assertThat(mapOfFruits.get('K')).hasSize(1);
91 | assertThat(mapOfFruits.get('M')).hasSize(1);
92 | assertThat(mapOfFruits.get('P')).hasSize(2);
93 | }
94 |
95 | //
96 | /*
97 | Solution 1.
98 |
99 | fruitBaskets.stream()
100 | .flatMap(Collection::stream)
101 | .collect(Collectors.toList());
102 |
103 | Solution 2 - just to illustrate the concept of flatMap.
104 |
105 | fruitBaskets.stream()
106 | .map(basket -> basket.stream())
107 | .reduce(Stream.empty(), Stream::concat)
108 | .collect(Collectors.toList());
109 |
110 | */
111 | //
112 | @Test
113 | @DisplayName("Task: Put all fruits into one basket")
114 | void task4() {
115 | final List> fruitBaskets = List.of(
116 | List.of(BANANA, PAPAYA),
117 | List.of(MANGO, PEACH)
118 | );
119 |
120 | final List basketWithAllFruits = Collections.emptyList(); // TODO: fruitBaskets.stream()
121 |
122 | assertThat(basketWithAllFruits).contains(BANANA, PAPAYA, MANGO, PEACH);
123 | assertThat(basketWithAllFruits).doesNotContain(KIWI);
124 | }
125 |
126 | //
127 | /*
128 | basket.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
129 | */
130 | //
131 | @Test
132 | @DisplayName("Task: Count amount of each fruit in the basket")
133 | void task5() {
134 | final List basket = List.of(MANGO, PAPAYA, MANGO, PEACH, KIWI, KIWI, KIWI);
135 |
136 | final Map countedFruit = Collections.emptyMap(); // TODO: basket.stream()
137 |
138 | assertThat(countedFruit.keySet()).contains(MANGO, PAPAYA, PEACH, KIWI);
139 |
140 | assertThat(countedFruit.get(MANGO)).isEqualTo(2);
141 | assertThat(countedFruit.get(PAPAYA)).isEqualTo(1);
142 | assertThat(countedFruit.get(PEACH)).isEqualTo(1);
143 | assertThat(countedFruit.get(KIWI)).isEqualTo(3);
144 | }
145 |
146 | //
147 | /*
148 | FRUITS.stream()
149 | .reduce(new Fruit("", 0), (mixedFruit, fruitToAdd) -> new Fruit(
150 | mixedFruit.getName() + fruitToAdd.getName(),
151 | mixedFruit.getCalories() + fruitToAdd.getCalories()
152 | ));
153 | */
154 | //
155 | @Test
156 | @DisplayName("Task: Mix all fruits together and construct one, big, new Fruit")
157 | void task6() {
158 | final Fruit bigJuicyFruit = null; // TODO: FRUITS.stream()
159 |
160 | assertThat(bigJuicyFruit).isNotNull();
161 | assertThat(bigJuicyFruit.getCalories()).isEqualTo(415);
162 | assertThat(bigJuicyFruit.getName()).isNotEmpty();
163 | }
164 |
165 | //
166 | /*
167 | final Stream infiniteStreamOfFruits = Stream
168 | .generate(randomFruitSupplier);
169 | */
170 | //
171 | @Test
172 | @DisplayName("Task: Generate list of 10 randomly picked fruits")
173 | void task7() {
174 |
175 | // Random fruit supplier
176 | final Supplier randomFruitSupplier = new Supplier<>() {
177 | final Random random = new Random();
178 | final List fruits = new ArrayList<>(FRUITS);
179 |
180 | @Override
181 | public Fruit get() {
182 | return fruits.get(random.nextInt(fruits.size()));
183 | }
184 | };
185 |
186 | final Stream infiniteStreamOfFruits = Stream.empty(); // TODO: Stream.
187 |
188 |
189 | List pickedFruits = infiniteStreamOfFruits
190 | .limit(10)
191 | .collect(Collectors.toList());
192 |
193 | assertThat(pickedFruits).hasSize(10);
194 | }
195 |
196 | //
197 | /*
198 | IntStream
199 | .range(0, fruitList.size())
200 | .filter(i -> i % 2 == 1)
201 | .mapToObj(fruitList::get)
202 | .collect(toList());
203 | */
204 | //
205 | @Test
206 | @DisplayName("Task: Collect only second and forth (with odd index) fruit from fruitList")
207 | void task8() {
208 | // Do you know why list have to be sorted?
209 | final List fruitList = new ArrayList<>(FRUITS).stream()
210 | .sorted(Comparator.comparing(Fruit::getName))
211 | .collect(toList());
212 |
213 | List filteredFruits = fruitList; // TODO: change to stream.
214 |
215 | assertThat(filteredFruits).hasSize(2);
216 | assertThat(filteredFruits).containsExactly(KIWI, PAPAYA);
217 | }
218 |
219 | }
220 |
--------------------------------------------------------------------------------
/src/test/java/com/github/hubertwo/kata/stream/basics/FibonacciSequenceTest.java:
--------------------------------------------------------------------------------
1 | package com.github.hubertwo.kata.stream.basics;
2 |
3 | import org.assertj.core.data.Percentage;
4 | import org.junit.jupiter.api.DisplayName;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import static org.assertj.core.api.Assertions.assertThat;
8 |
9 |
10 | /**
11 | * This task you will show you how to use:
12 | *
13 | * - {@link java.util.stream.Stream#iterate)}
14 | * - {@link java.util.stream.Stream#reduce)}
15 | *
16 | *
17 | * @author https://github.com/HubertWo
18 | */
19 | @DisplayName("Fibonacci Sequence")
20 | class FibonacciSequenceTest {
21 |
22 | //
23 | /*
24 | return Stream
25 | .iterate(new long[]{1, 1}, (long[] results) -> new long[]{results[1], results[0] + results[1]})
26 | .limit(sequenceIndex)
27 | .reduce((a, b) -> b)
28 | .orElse(new long[]{0, 0})[0];
29 | */
30 | //
31 |
32 | /**
33 | * Calculates {@param sequenceIndex} of Fibonacci sequence.
34 | *
35 | * @see Wikipedia
36 | */
37 | static long fibonacciSequence(long sequenceIndex) {
38 | throw new IllegalStateException("Not implemented yet");
39 | }
40 |
41 | @Test
42 | @DisplayName("Task: Calculate Fibonacci Sequence")
43 | void task() {
44 | assertThat(fibonacciSequence(0)).isEqualTo(0);
45 | assertThat(fibonacciSequence(1)).isEqualTo(1);
46 | assertThat(fibonacciSequence(2)).isEqualTo(1);
47 | assertThat(fibonacciSequence(3)).isEqualTo(2);
48 | assertThat(fibonacciSequence(10)).isEqualTo(55);
49 |
50 | final double goldenRatio = (double) fibonacciSequence(20) / fibonacciSequence(19);
51 | assertThat(goldenRatio).isCloseTo(1.61d, Percentage.withPercentage(2));
52 | }
53 |
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/test/java/com/github/hubertwo/kata/stream/basics/PalindromeTest.java:
--------------------------------------------------------------------------------
1 | package com.github.hubertwo.kata.stream.basics;
2 |
3 | import org.junit.jupiter.api.DisplayName;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import java.util.function.Function;
7 | import java.util.stream.Collectors;
8 | import java.util.stream.Stream;
9 |
10 | import static org.assertj.core.api.Assertions.assertThat;
11 |
12 | /**
13 | * This task you will show you how to use:
14 | *
15 | * - {@link Collectors#groupingBy(Function)}}
16 | * - {@link Function#identity()}
17 | * - {@link Collectors#counting()}
18 | * - {@link Stream#count()}
19 | *
20 | *
21 | * @author https://github.com/HubertWo
22 | */
23 | @DisplayName("Palindrome")
24 | class PalindromeTest {
25 |
26 | /**
27 | * Word is an palindrome candidate when each character of word occurs even number of
28 | * times or only one character occurs odd number of times.
29 | *
30 | * @return true if {@param word} is an palindrome candidate
31 | */
32 | //
33 | /*
34 | if (word.length() == 0) {
35 | return false;
36 | }
37 |
38 | final Map countedCharacters = word
39 | .chars()
40 | .boxed()
41 | .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
42 |
43 | // Count number of characters which occurred odd number of times
44 | final long oddCharactersCount = countedCharacters.values().stream()
45 | .filter(count -> count % 2 != 0)
46 | .count();
47 |
48 | // Only one character with odd number of occurrences is allowed
49 | return oddCharactersCount <= 1;
50 | */
51 | //
52 | private static boolean isPalindromeCandidate(final String word) {
53 | // TODO: implement using {@link Stream}
54 | throw new IllegalStateException("Not implemented yet");
55 | }
56 |
57 | @Test
58 | @DisplayName("Is palindrome candidate")
59 | void palindromeCandidate() {
60 | assertThat(isPalindromeCandidate("")).isFalse();
61 | assertThat(isPalindromeCandidate("a")).isTrue();
62 | assertThat(isPalindromeCandidate("ab")).isFalse();
63 | assertThat(isPalindromeCandidate("aab")).isTrue();
64 | assertThat(isPalindromeCandidate("aabb")).isTrue();
65 | assertThat(isPalindromeCandidate("aabbc")).isTrue();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/test/resources/java11/fruitList.txt:
--------------------------------------------------------------------------------
1 | Mango,107
2 | Kiwi,46
3 | Papaya,109
4 | Peach,48
5 | Banana,105
--------------------------------------------------------------------------------