├── 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 predicate) { 29 | return new Spliterators.AbstractSpliterator(spliterator.estimateSize(), 0) { 30 | boolean stillGoing = true; 31 | @Override public boolean tryAdvance(Consumer 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 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 | --------------------------------------------------------------------------------