├── README.md
├── pom.xml
└── src
└── main
└── java
└── com
└── xpinjection
└── java8
└── extensions
├── Annotations.java
├── Permission.java
├── Person.java
└── stream
├── AddElementsToStream.java
├── CheckedExceptions.java
├── DistinctByProperty.java
├── ExceptionHandling.java
├── InvertMap.java
├── JoinValues.java
├── RankedItems.java
└── TakeWhile.java
/README.md:
--------------------------------------------------------------------------------
1 | # java8-extensions
2 | Code samples demonstrating benefits of some Java 8 extensions and libraries
3 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.xpinjection
8 | java8-extensions
9 | 1.0-SNAPSHOT
10 |
11 | Java 8 extentions
12 | Code samples demonstrating benefits of some Java 8 extensions and libraries
13 |
14 |
15 |
16 |
17 | org.apache.maven.plugins
18 | maven-compiler-plugin
19 |
20 | 1.8
21 | 1.8
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | org.jooq
30 | jool
31 | 0.9.12
32 |
33 |
34 | one.util
35 | streamex
36 | 0.6.5
37 |
38 |
39 | io.vavr
40 | vavr
41 | 0.9.0
42 |
43 |
44 | org.projectlombok
45 | lombok
46 | 1.16.18
47 | provided
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/main/java/com/xpinjection/java8/extensions/Annotations.java:
--------------------------------------------------------------------------------
1 | package com.xpinjection.java8.extensions;
2 |
3 | public class Annotations {
4 | public @interface Good{}
5 | public @interface Bad{}
6 | public @interface Ugly{}
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/com/xpinjection/java8/extensions/Permission.java:
--------------------------------------------------------------------------------
1 | package com.xpinjection.java8.extensions;
2 |
3 | public enum Permission {
4 | READ, WRITE, EDIT, ADMIN
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/com/xpinjection/java8/extensions/Person.java:
--------------------------------------------------------------------------------
1 | package com.xpinjection.java8.extensions;
2 |
3 | import lombok.Data;
4 | import lombok.RequiredArgsConstructor;
5 |
6 | @Data
7 | @RequiredArgsConstructor
8 | public class Person {
9 | private Long id;
10 |
11 | private final String name;
12 | private final String surname;
13 | private final int age;
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/xpinjection/java8/extensions/stream/AddElementsToStream.java:
--------------------------------------------------------------------------------
1 | package com.xpinjection.java8.extensions.stream;
2 |
3 | import com.xpinjection.java8.extensions.Annotations.Good;
4 | import com.xpinjection.java8.extensions.Annotations.Ugly;
5 | import io.vavr.collection.List;
6 | import one.util.streamex.StreamEx;
7 | import org.jooq.lambda.Seq;
8 |
9 | import java.util.Arrays;
10 | import java.util.stream.Stream;
11 |
12 | import static java.util.stream.Stream.concat;
13 |
14 | public class AddElementsToStream {
15 | @Ugly
16 | void printHtmlStructure(String... tokens) {
17 | concat(
18 | Stream.of(""),
19 | concat(Arrays.stream(tokens).filter(this::isHtmlTag),
20 | Stream.of(""))
21 | ).forEach(System.out::println);
22 | }
23 |
24 | @Good
25 | void printHtmlStructureWithJool(String... tokens) {
26 | Seq.of(tokens)
27 | .filter(this::isHtmlTag)
28 | .prepend("")
29 | .append("")
30 | .forEach(System.out::println);
31 | }
32 |
33 | @Good
34 | void printHtmlStructureWithVavr(String... tokens) {
35 | List.of(tokens)
36 | .filter(this::isHtmlTag)
37 | .prepend("")
38 | .append("")
39 | .forEach(System.out::println);
40 | }
41 |
42 | @Good
43 | void printHtmlStructureWithStreamEx(String... tokens) {
44 | StreamEx.of(tokens)
45 | .filter(this::isHtmlTag)
46 | .prepend("")
47 | .append("")
48 | .forEach(System.out::println);
49 | }
50 |
51 | private boolean isHtmlTag(String token) {
52 | return token.startsWith("<") && token.endsWith(">");
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/xpinjection/java8/extensions/stream/CheckedExceptions.java:
--------------------------------------------------------------------------------
1 | package com.xpinjection.java8.extensions.stream;
2 |
3 | import com.xpinjection.java8.extensions.Annotations.Good;
4 | import io.vavr.collection.List;
5 | import io.vavr.control.Try;
6 | import org.jooq.lambda.Unchecked;
7 |
8 | import java.io.File;
9 | import java.io.IOException;
10 | import java.util.Arrays;
11 |
12 | import static com.xpinjection.java8.extensions.Annotations.Ugly;
13 |
14 | public class CheckedExceptions {
15 | @Ugly
16 | void printFilesInDir(File dir) {
17 | Arrays.stream(dir.listFiles()).map(file -> {
18 | try {
19 | return file.getCanonicalPath();
20 | } catch (IOException e) {
21 | throw new IllegalStateException("Can't access file", e);
22 | }
23 | }).forEach(System.out::println);
24 | }
25 |
26 | @Good
27 | void printFilesInDirWithJool(File dir) {
28 | Arrays.stream(dir.listFiles())
29 | .map(Unchecked.function(File::getCanonicalPath,
30 | e -> { throw new IllegalStateException("Can't access file", e); }))
31 | .forEach(System.out::println);
32 | }
33 |
34 | @Good
35 | void printFilesInDirWithVavr(File dir) {
36 | List.of(dir.listFiles())
37 | .map(file -> Try.ofCallable(file::getCanonicalPath)
38 | .getOrElseThrow(e -> new IllegalStateException("Can't access file", e)))
39 | .forEach(System.out::println);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/xpinjection/java8/extensions/stream/DistinctByProperty.java:
--------------------------------------------------------------------------------
1 | package com.xpinjection.java8.extensions.stream;
2 |
3 | import com.xpinjection.java8.extensions.Annotations.Good;
4 | import com.xpinjection.java8.extensions.Annotations.Ugly;
5 | import com.xpinjection.java8.extensions.Person;
6 | import one.util.streamex.StreamEx;
7 | import org.jooq.lambda.Seq;
8 |
9 | import java.util.HashSet;
10 | import java.util.List;
11 | import java.util.Set;
12 |
13 | import static java.util.stream.Collectors.toList;
14 |
15 | public class DistinctByProperty {
16 | @Ugly
17 | List filterByName(List people) {
18 | Set names = new HashSet<>();
19 | return people.stream()
20 | .filter(person -> names.add(person.getName()))
21 | .collect(toList());
22 | }
23 |
24 | @Ugly
25 | List filterByNameWithVavr(List people) {
26 | return io.vavr.collection.List.ofAll(people)
27 | .distinctBy(Person::getName)
28 | .toJavaList();
29 | }
30 |
31 | @Good
32 | List filterByNameWithStreamEx(List people) {
33 | return StreamEx.of(people)
34 | .distinct(Person::getName)
35 | .toList();
36 | }
37 |
38 | @Good
39 | List filterByNameWithJool(List people) {
40 | return Seq.seq(people)
41 | .distinct(Person::getName)
42 | .toList();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/xpinjection/java8/extensions/stream/ExceptionHandling.java:
--------------------------------------------------------------------------------
1 | package com.xpinjection.java8.extensions.stream;
2 |
3 | import com.xpinjection.java8.extensions.Annotations.Good;
4 | import com.xpinjection.java8.extensions.Annotations.Ugly;
5 | import com.xpinjection.java8.extensions.Permission;
6 | import io.vavr.control.Try;
7 |
8 | import java.util.EnumSet;
9 | import java.util.Set;
10 |
11 | public class ExceptionHandling {
12 | @Ugly
13 | Set getUserPermissions(long userId) {
14 | try {
15 | return retrievePermissions(userId);
16 | } catch (RuntimeException e) {
17 | System.out.println(e);
18 | return EnumSet.of(Permission.READ);
19 | }
20 | }
21 |
22 | @Good
23 | Set getUserPermissionsWithVavr(long userId) {
24 | return Try.ofSupplier(() -> retrievePermissions(userId))
25 | .onFailure(System.out::println)
26 | .getOrElse(EnumSet.of(Permission.READ));
27 | }
28 |
29 | private Set retrievePermissions(long userId) {
30 | //connect to some external service
31 | return EnumSet.noneOf(Permission.class);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/xpinjection/java8/extensions/stream/InvertMap.java:
--------------------------------------------------------------------------------
1 | package com.xpinjection.java8.extensions.stream;
2 |
3 | import com.xpinjection.java8.extensions.Annotations.Good;
4 | import com.xpinjection.java8.extensions.Annotations.Ugly;
5 | import com.xpinjection.java8.extensions.Permission;
6 | import com.xpinjection.java8.extensions.Person;
7 | import io.vavr.Tuple;
8 | import one.util.streamex.EntryStream;
9 | import org.jooq.lambda.Seq;
10 | import org.jooq.lambda.tuple.Tuple2;
11 |
12 | import java.util.*;
13 |
14 | import static java.util.stream.Collectors.*;
15 | import static org.jooq.lambda.tuple.Tuple.tuple;
16 |
17 | public class InvertMap {
18 | @Ugly
19 | Map> groupByPerson(Map> permissions) {
20 | return permissions.entrySet().stream()
21 | .flatMap(entry -> entry.getValue().stream()
22 | .map(person -> new AbstractMap.SimpleEntry<>(person, entry.getKey())))
23 | .collect(groupingBy(Map.Entry::getKey,
24 | mapping(Map.Entry::getValue, toSet())));
25 | }
26 |
27 | @Good
28 | Map> groupByPersonWithStreamEx(Map> permissions) {
29 | return EntryStream.of(permissions)
30 | .flatMapValues(List::stream)
31 | .invert()
32 | .groupingTo(HashSet::new);
33 | }
34 |
35 | @Good
36 | Map> groupByPersonWithJool(Map> permissions) {
37 | return Seq.seq(permissions)
38 | .flatMap(t -> t.v2.stream()
39 | .map(person -> tuple(person, t.v1)))
40 | .groupBy(Tuple2::v1, mapping(Tuple2::v2, toSet()));
41 | }
42 |
43 | @Good
44 | Map> groupByPersonWithVavr(Map> permissions) {
45 | return io.vavr.collection.HashMap.ofAll(permissions)
46 | .flatMap(t -> io.vavr.collection.List.ofAll(t._2)
47 | .map(person -> Tuple.of(person, t._1)))
48 | .collect(groupingBy(io.vavr.Tuple2::_1,
49 | mapping(io.vavr.Tuple2::_2, toSet())));
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/xpinjection/java8/extensions/stream/JoinValues.java:
--------------------------------------------------------------------------------
1 | package com.xpinjection.java8.extensions.stream;
2 |
3 | import com.xpinjection.java8.extensions.Annotations.Good;
4 | import com.xpinjection.java8.extensions.Annotations.Ugly;
5 | import io.vavr.collection.List;
6 | import one.util.streamex.StreamEx;
7 | import org.jooq.lambda.Seq;
8 |
9 | import java.util.Arrays;
10 | import java.util.stream.Collectors;
11 |
12 | public class JoinValues {
13 | @Ugly
14 | String joinWithPlainJava(String... words) {
15 | StringBuilder builder = new StringBuilder();
16 | for (String s : words) {
17 | if (builder.length() > 0) {
18 | builder.append(", ");
19 | }
20 | builder.append(s);
21 | }
22 | return builder.toString();
23 | }
24 |
25 | @Good
26 | String joinWithStreamAPI(String... words) {
27 | return Arrays.stream(words).collect(Collectors.joining(", "));
28 | }
29 |
30 | @Good
31 | String joinWithStreamEx(String... words) {
32 | return StreamEx.of(words).joining(", ");
33 | }
34 |
35 | @Good
36 | String joinWithVavr(String... words) {
37 | return List.of(words).mkString(", ");
38 | }
39 |
40 | @Good
41 | String joinWithJool(String... words) {
42 | return Seq.of(words).toString(", ");
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/xpinjection/java8/extensions/stream/RankedItems.java:
--------------------------------------------------------------------------------
1 | package com.xpinjection.java8.extensions.stream;
2 |
3 | import com.xpinjection.java8.extensions.Annotations.Good;
4 | import com.xpinjection.java8.extensions.Annotations.Ugly;
5 | import io.vavr.collection.List;
6 | import one.util.streamex.StreamEx;
7 | import org.jooq.lambda.Seq;
8 |
9 | import java.util.Arrays;
10 | import java.util.stream.IntStream;
11 |
12 | public class RankedItems {
13 | @Ugly
14 | void rankByNaturalOrderWithOldJava(String... words) {
15 | String[] sorted = Arrays.copyOf(words, words.length);
16 | Arrays.sort(sorted);
17 | for (int i = 0; i < sorted.length; i++) {
18 | System.out.println(i + ". " + sorted[i]);
19 | }
20 | }
21 |
22 | @Ugly
23 | void rankByNaturalOrder(String... words) {
24 | String[] sorted = Arrays.copyOf(words, words.length);
25 | Arrays.sort(sorted);
26 | IntStream.range(0, words.length)
27 | .mapToObj(i -> i + ". " + sorted[i])
28 | .forEach(System.out::println);
29 | }
30 |
31 | @Good
32 | void rankByNaturalOrderWithJool(String... words) {
33 | Seq.of(words)
34 | .sorted()
35 | .zipWithIndex()
36 | .map(t -> t.v2 + ". " + t.v1)
37 | .forEach(System.out::println);
38 | }
39 |
40 | @Good
41 | void rankByNaturalOrderWithVavr(String... words) {
42 | List.of(words)
43 | .sorted()
44 | .zipWithIndex()
45 | .map(t -> t._2 + ". " + t._1)
46 | .forEach(System.out::println);
47 | }
48 |
49 | @Good
50 | void rankByNaturalOrderWithStreamEx(String... words) {
51 | StreamEx.of(words)
52 | .sorted()
53 | .zipWith(IntStream.range(0, words.length).boxed())
54 | .join(". ")
55 | .forEach(System.out::println);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/xpinjection/java8/extensions/stream/TakeWhile.java:
--------------------------------------------------------------------------------
1 | package com.xpinjection.java8.extensions.stream;
2 |
3 | import com.xpinjection.java8.extensions.Annotations.Good;
4 | import com.xpinjection.java8.extensions.Annotations.Ugly;
5 | import io.vavr.collection.List;
6 | import one.util.streamex.StreamEx;
7 | import org.jooq.lambda.Seq;
8 |
9 | import java.util.Arrays;
10 | import java.util.Spliterator;
11 | import java.util.Spliterators;
12 | import java.util.function.Consumer;
13 | import java.util.function.Predicate;
14 | import java.util.stream.Stream;
15 | import java.util.stream.StreamSupport;
16 |
17 | public class TakeWhile {
18 | @Ugly
19 | void takeAllUntilStopWithOldJava(String... words) {
20 | for (String word : words) {
21 | if ("STOP".equals(word)) {
22 | return;
23 | }
24 | System.out.println(word);
25 | }
26 | }
27 |
28 | private Spliterator takeWhile(Spliterator spliterator, Predicate super T> predicate) {
29 | return new Spliterators.AbstractSpliterator(spliterator.estimateSize(), 0) {
30 | boolean stillGoing = true;
31 | @Override public boolean tryAdvance(Consumer super T> consumer) {
32 | if (stillGoing) {
33 | boolean hadNext = spliterator.tryAdvance(elem -> {
34 | if (predicate.test(elem)) {
35 | consumer.accept(elem);
36 | } else {
37 | stillGoing = false;
38 | }
39 | });
40 | return hadNext && stillGoing;
41 | }
42 | return false;
43 | }
44 | };
45 | }
46 |
47 | private Stream takeWhile(Stream stream, Predicate super T> predicate) {
48 | return StreamSupport.stream(takeWhile(stream.spliterator(), predicate), false);
49 | }
50 |
51 | @Ugly
52 | void takeAllUntilStop(String... words) {
53 | takeWhile(Arrays.stream(words), word -> !"STOP".equals(word))
54 | .forEach(System.out::println);
55 | }
56 |
57 | @Good
58 | void takeAllUntilStopWithJool(String... words) {
59 | Seq.of(words)
60 | .limitUntil("STOP"::equals)
61 | .forEach(System.out::println);
62 | }
63 |
64 | @Good
65 | void takeAllUntilStopWithVavr(String... words) {
66 | List.of(words)
67 | .takeUntil("STOP"::equals)
68 | .forEach(System.out::println);
69 | }
70 |
71 | @Good
72 | void takeAllUntilStopWithStreamEx(String... words) {
73 | StreamEx.of(words)
74 | .takeWhile(word -> !"STOP".equals(word))
75 | .forEach(System.out::println);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------