├── .gitignore ├── src ├── main │ ├── java │ │ └── pl │ │ │ └── piomin │ │ │ └── java │ │ │ └── samples │ │ │ ├── sealedclasses │ │ │ ├── Tiger.java │ │ │ ├── Cat.java │ │ │ ├── Dog.java │ │ │ └── Pet.java │ │ │ ├── records │ │ │ ├── Person.java │ │ │ ├── PersonWithAddress.java │ │ │ └── PersonOld.java │ │ │ ├── helper │ │ │ ├── Bar.java │ │ │ ├── Foo.java │ │ │ ├── Employee.java │ │ │ ├── ColorOfRainbow.java │ │ │ ├── Organization.java │ │ │ ├── PersonEntity.java │ │ │ ├── Balance.java │ │ │ └── DelayedEvent.java │ │ │ ├── spi │ │ │ ├── GreetingService.java │ │ │ ├── HiGreetingService.java │ │ │ └── HelloGreetingService.java │ │ │ ├── localvar │ │ │ └── LocalVar.java │ │ │ ├── optional │ │ │ ├── PersonRepository.java │ │ │ └── OptionalMethods.java │ │ │ ├── mapper │ │ │ └── PersonMapper.java │ │ │ ├── privatemethods │ │ │ └── ExampleInterface.java │ │ │ ├── textblocks │ │ │ └── TextBlockString.java │ │ │ ├── unmodifiablecollections │ │ │ └── CollectionsCreator.java │ │ │ └── switches │ │ │ └── SwitchComparison.java │ └── resources │ │ └── META-INF │ │ └── services │ │ └── pl.piomin.java.samples.spi.GreetingService └── test │ └── java │ └── pl │ └── piomin │ └── java │ └── samples │ ├── stringtemplates │ └── StringTemplatesTests.java │ ├── records │ └── PersonTests.java │ ├── format │ └── FormatTests.java │ ├── textblocks │ └── TextBlockTests.java │ ├── spi │ └── SpiTests.java │ ├── mapper │ └── MapperTests.java │ ├── enums │ └── EnumSetTest.java │ ├── switches │ └── SwitchComparisonTests.java │ ├── delay │ └── DelayTest.java │ ├── structuredconcurrency │ └── StructuredConcurrencyTests.java │ ├── collections │ └── SequencedCollectionTests.java │ └── unmodifiablecollections │ ├── CollectionsCreatorTest.java │ └── EclipseCollectionsTest.java ├── renovate.json ├── .circleci └── config.yml ├── readme.md └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # Project exclude paths 2 | /target/ -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/sealedclasses/Tiger.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.sealedclasses; 2 | 3 | public class Tiger { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/records/Person.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.records; 2 | 3 | public record Person(String name, int age) {} 4 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/sealedclasses/Cat.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.sealedclasses; 2 | 3 | public final class Cat extends Pet { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/helper/Bar.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.helper; 2 | 3 | public interface Bar { 4 | 5 | String callBar(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/helper/Foo.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.helper; 2 | 3 | public interface Foo { 4 | 5 | String callFoo(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/sealedclasses/Dog.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.sealedclasses; 2 | 3 | public non-sealed class Dog extends Pet { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/sealedclasses/Pet.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.sealedclasses; 2 | 3 | public abstract sealed class Pet permits Cat, Dog { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/pl.piomin.java.samples.spi.GreetingService: -------------------------------------------------------------------------------- 1 | pl.piomin.java.samples.spi.HiGreetingService 2 | pl.piomin.java.samples.spi.HelloGreetingService -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/helper/Employee.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.helper; 2 | 3 | public record Employee(Integer id, String name, String position) { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/spi/GreetingService.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.spi; 2 | 3 | public interface GreetingService { 4 | 5 | String greet(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/helper/ColorOfRainbow.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.helper; 2 | 3 | public enum ColorOfRainbow { 4 | RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/helper/Organization.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.helper; 2 | 3 | import java.util.List; 4 | 5 | public record Organization(String name, List employees) { 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/records/PersonWithAddress.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.records; 2 | 3 | import java.util.Date; 4 | 5 | public record PersonWithAddress(String name, Date birthday, String address) { 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/spi/HiGreetingService.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.spi; 2 | 3 | public class HiGreetingService implements GreetingService { 4 | @Override 5 | public String greet() { 6 | return "Hi"; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/spi/HelloGreetingService.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.spi; 2 | 3 | public class HelloGreetingService implements GreetingService { 4 | @Override 5 | public String greet() { 6 | return "Hello"; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/helper/PersonEntity.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.helper; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class PersonEntity { 9 | private String fullName; 10 | private int age; 11 | } 12 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base",":dependencyDashboard" 5 | ], 6 | "packageRules": [ 7 | { 8 | "matchUpdateTypes": ["minor", "patch", "pin", "digest"], 9 | "automerge": true 10 | } 11 | ], 12 | "prCreation": "not-pending" 13 | } -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/localvar/LocalVar.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.localvar; 2 | 3 | import java.util.function.BiFunction; 4 | 5 | public class LocalVar { 6 | 7 | public String sumOfString() { 8 | BiFunction func = (var x, var y) -> x + y; 9 | return func.apply("abc", "efg"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/optional/PersonRepository.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.optional; 2 | 3 | import pl.piomin.java.samples.records.Person; 4 | 5 | import java.util.Optional; 6 | 7 | public class PersonRepository { 8 | 9 | public Optional findById(Long id) { 10 | return Optional.of(new Person("TestName", 30)); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/helper/Balance.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.helper; 2 | 3 | public class Balance { 4 | private int amount; 5 | 6 | public Balance(int amount) { 7 | this.amount = amount; 8 | } 9 | 10 | public int getAmount() { 11 | return amount; 12 | } 13 | 14 | public void setAmount(int amount) { 15 | this.amount = amount; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/mapper/PersonMapper.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.mapper; 2 | 3 | import org.mapstruct.Mapper; 4 | import org.mapstruct.Mapping; 5 | import pl.piomin.java.samples.helper.PersonEntity; 6 | import pl.piomin.java.samples.records.Person; 7 | 8 | @Mapper 9 | public interface PersonMapper { 10 | 11 | @Mapping(source = "fullName", target = "name") 12 | Person mapToDto(PersonEntity personEntity); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/privatemethods/ExampleInterface.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.privatemethods; 2 | 3 | public interface ExampleInterface { 4 | 5 | private void printMsg(String methodName) { 6 | System.out.println("Calling interface"); 7 | System.out.println("Interface method: " + methodName); 8 | } 9 | 10 | default void method1() { 11 | printMsg("method1"); 12 | } 13 | 14 | default void method2() { 15 | printMsg("method2"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | jobs: 4 | build: 5 | docker: 6 | - image: 'cimg/openjdk:21.0.9' 7 | steps: 8 | - checkout 9 | - run: 10 | name: Analyze on SonarCloud 11 | command: mvn verify sonar:sonar 12 | 13 | executors: 14 | jdk: 15 | docker: 16 | - image: 'cimg/openjdk:21.0.9' 17 | 18 | orbs: 19 | maven: circleci/maven@2.1.1 20 | 21 | workflows: 22 | maven_test: 23 | jobs: 24 | - maven/test: 25 | executor: jdk 26 | - build: 27 | context: SonarCloud -------------------------------------------------------------------------------- /src/test/java/pl/piomin/java/samples/stringtemplates/StringTemplatesTests.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.stringtemplates; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static java.lang.StringTemplate.STR; 6 | 7 | public class StringTemplatesTests { 8 | 9 | @Test 10 | void shouldBePrinted() { 11 | String firstName = "Piotr"; 12 | String lastName = "Minkowski"; 13 | String greetings = STR."Greetings from \{firstName} \{lastName}"; 14 | assert greetings.equals("Greetings from Piotr Minkowski"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/pl/piomin/java/samples/records/PersonTests.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.records; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | public class PersonTests { 7 | 8 | private static final String NAME = "John Smith"; 9 | private static final int AGE = 50; 10 | 11 | @Test 12 | void shouldHaveGetters() { 13 | Person person = new Person(NAME, AGE); 14 | Assertions.assertEquals(NAME, person.name()); 15 | Assertions.assertEquals(AGE, person.age()); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/helper/DelayedEvent.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.helper; 2 | 3 | import java.util.concurrent.Delayed; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | public record DelayedEvent(long startTime, String msg) implements Delayed { 7 | 8 | public long getDelay(TimeUnit unit) { 9 | long diff = startTime - System.currentTimeMillis(); 10 | return unit.convert(diff, TimeUnit.MILLISECONDS); 11 | } 12 | 13 | public int compareTo(Delayed o) { 14 | return (int) (this.startTime - ((DelayedEvent) o).startTime); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/pl/piomin/java/samples/format/FormatTests.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.format; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.Arrays; 6 | import java.util.HexFormat; 7 | 8 | public class FormatTests { 9 | 10 | @Test 11 | void hex() { 12 | HexFormat format = HexFormat.of(); 13 | 14 | byte[] input = new byte[] {127, 0, -50, 105}; 15 | String hex = format.formatHex(input); 16 | System.out.println(hex); 17 | 18 | byte[] output = format.parseHex(hex); 19 | assert Arrays.compare(input, output) == 0; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/textblocks/TextBlockString.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.textblocks; 2 | 3 | public class TextBlockString { 4 | 5 | public String getOldPrettyPrintJson() { 6 | return "{\n" + 7 | " \"firstName\": \"Piotr\",\n" + 8 | " \"lastName\": \"Mińkowski\"\n" + 9 | "}\n"; 10 | } 11 | 12 | public String getNewPrettyPrintJson() { 13 | return """ 14 | { 15 | "firstName": "Piotr", 16 | "lastName": "Mińkowski" 17 | } 18 | """; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/pl/piomin/java/samples/textblocks/TextBlockTests.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.textblocks; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | public class TextBlockTests { 7 | 8 | @Test 9 | void shouldBeTheSame() { 10 | TextBlockString textBlockString = new TextBlockString(); 11 | System.out.println(textBlockString.getOldPrettyPrintJson()); 12 | System.out.println(textBlockString.getNewPrettyPrintJson()); 13 | Assertions.assertEquals(textBlockString.getOldPrettyPrintJson(), 14 | textBlockString.getNewPrettyPrintJson()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/pl/piomin/java/samples/spi/SpiTests.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.spi; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.ServiceLoader; 6 | 7 | public class SpiTests { 8 | 9 | @Test 10 | void greeting() { 11 | ServiceLoader sl = ServiceLoader.load(GreetingService.class); 12 | sl.iterator().forEachRemaining(gs -> System.out.println(gs.greet())); 13 | } 14 | 15 | // @Test 16 | void shutdownHook() { 17 | Thread shutdownThread = new Thread(() -> System.out.println("Hook")); 18 | shutdownThread.setDaemon(true); 19 | Runtime.getRuntime().addShutdownHook(shutdownThread); 20 | System.exit(0); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/pl/piomin/java/samples/mapper/MapperTests.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.mapper; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | import org.mapstruct.factory.Mappers; 6 | import pl.piomin.java.samples.helper.PersonEntity; 7 | import pl.piomin.java.samples.records.Person; 8 | 9 | public class MapperTests { 10 | 11 | @Test 12 | void mappingPerson() { 13 | PersonEntity personEntity = new PersonEntity(); 14 | personEntity.setFullName("Piotr Minkowski"); 15 | personEntity.setAge(10); 16 | 17 | PersonMapper mapper = Mappers.getMapper(PersonMapper.class); 18 | Person person = mapper.mapToDto(personEntity); 19 | Assertions.assertNotNull(person); 20 | Assertions.assertEquals(10, person.age()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/pl/piomin/java/samples/enums/EnumSetTest.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.enums; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import pl.piomin.java.samples.helper.Bar; 5 | import pl.piomin.java.samples.helper.ColorOfRainbow; 6 | import pl.piomin.java.samples.helper.Foo; 7 | 8 | import java.util.EnumSet; 9 | 10 | public class EnumSetTest { 11 | 12 | @Test 13 | void test() { 14 | EnumSet all = EnumSet.allOf(ColorOfRainbow.class); 15 | EnumSet part = EnumSet.range(ColorOfRainbow.ORANGE, ColorOfRainbow.BLUE); 16 | part.removeIf(c -> c.name().length() > 5); 17 | System.out.println(part); 18 | assert part.size() == 2; 19 | EnumSet c = EnumSet.complementOf(part); 20 | System.out.println(c); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/pl/piomin/java/samples/switches/SwitchComparisonTests.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.switches; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | import pl.piomin.java.samples.sealedclasses.Cat; 6 | 7 | public class SwitchComparisonTests { 8 | 9 | @Test 10 | void switchWithoutBreak() { 11 | SwitchComparison switchComparison = new SwitchComparison(); 12 | String x = switchComparison.oldSwitchWithBreak(1); 13 | Assertions.assertEquals("one", x); 14 | } 15 | 16 | @Test 17 | void switchPatternMatching() { 18 | Cat c = new Cat(); 19 | SwitchComparison switchComparison = new SwitchComparison(); 20 | String x = switchComparison.newSwitchWithPatternMatching(c); 21 | Assertions.assertEquals("cat", x); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/pl/piomin/java/samples/delay/DelayTest.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.delay; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.junit.jupiter.api.Test; 5 | import pl.piomin.java.samples.helper.DelayedEvent; 6 | 7 | import java.time.LocalDateTime; 8 | import java.time.format.DateTimeFormatter; 9 | import java.util.concurrent.DelayQueue; 10 | import java.util.logging.Logger; 11 | 12 | public class DelayTest { 13 | 14 | Logger log = Logger.getLogger("DelayTest"); 15 | 16 | @Test 17 | void delay() throws InterruptedException { 18 | final DelayQueue delayQueue = new DelayQueue<>(); 19 | final long timeFirst = System.currentTimeMillis() + 10000; 20 | delayQueue.offer(new DelayedEvent(timeFirst, "1")); 21 | log.info("Done"); 22 | log.info(delayQueue.take().msg()); 23 | } 24 | 25 | @Test 26 | void formatter() { 27 | String s = DateTimeFormatter.ofPattern("B").format(LocalDateTime.now()); 28 | System.out.println(s); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/unmodifiablecollections/CollectionsCreator.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.unmodifiablecollections; 2 | 3 | import pl.piomin.java.samples.privatemethods.ExampleInterface; 4 | 5 | import java.util.*; 6 | 7 | public class CollectionsCreator { 8 | 9 | private List fruits = List.of("apple", "banana", "orange"); 10 | private Map numbers = Map.of(1, "one", 2,"two", 3, "three"); 11 | 12 | 13 | public List fruits() { 14 | List fruitsTmp = new ArrayList<>(); 15 | fruitsTmp.add("apple"); 16 | fruitsTmp.add("banana"); 17 | fruitsTmp.add("orange"); 18 | return Collections.unmodifiableList(fruitsTmp); 19 | } 20 | 21 | public List fruitsFromArray() { 22 | String[] fruitsArray = {"apple", "banana", "orange"}; 23 | return Arrays.asList(fruitsArray); 24 | } 25 | 26 | public Map numbers() { 27 | Map numbersTmp = new HashMap<>(); 28 | numbersTmp.put(1, "one"); 29 | numbersTmp.put(2, "two"); 30 | numbersTmp.put(3, "three"); 31 | return Collections.unmodifiableMap(numbersTmp); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/records/PersonOld.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.records; 2 | 3 | import java.util.Objects; 4 | 5 | public class PersonOld { 6 | 7 | private final String name; 8 | private int age; 9 | 10 | public PersonOld(String name, int age) { 11 | this.name = name; 12 | this.age = age; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public int getAge() { 20 | System.out.println("Age: " + this.age); 21 | return age; 22 | } 23 | 24 | public void setAge(int age) { 25 | this.age = age; 26 | } 27 | 28 | @Override 29 | public boolean equals(Object o) { 30 | if (this == o) return true; 31 | if (o == null || getClass() != o.getClass()) return false; 32 | PersonOld personOld = (PersonOld) o; 33 | return age == personOld.age && name.equals(personOld.name); 34 | } 35 | 36 | @Override 37 | public int hashCode() { 38 | return Objects.hash(name, age); 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "PersonOld{" + 44 | "name='" + name + '\'' + 45 | ", age=" + age + 46 | '}'; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # New Features of Java After 8 [![Twitter](https://img.shields.io/twitter/follow/piotr_minkowski.svg?style=social&logo=twitter&label=Follow%20Me)](https://twitter.com/piotr_minkowski) 2 | 3 | [![CircleCI](https://circleci.com/gh/piomin/sample-java-new-features.svg?style=svg)](https://circleci.com/gh/piomin/sample-java-new-features) 4 | 5 | [![SonarCloud](https://sonarcloud.io/images/project_badges/sonarcloud-black.svg)](https://sonarcloud.io/dashboard?id=piomin_sample-java-new-features) 6 | [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=piomin_sample-java-new-features&metric=bugs)](https://sonarcloud.io/dashboard?id=piomin_sample-spring-microservices-new) 7 | [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=piomin_sample-java-new-features&metric=coverage)](https://sonarcloud.io/dashboard?id=piomin_sample-spring-microservices-new) 8 | [![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=piomin_sample-java-new-features&metric=ncloc)](https://sonarcloud.io/dashboard?id=piomin_sample-spring-microservices-new) 9 | 10 | Examples illustrating the most interesting developer-friendly features after Java 8 described in the following article: [New Developer Friendly Features After Java 8](https://piotrminkowski.com/2021/02/01/new-developer-friendly-features-after-java-8/) 11 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/optional/OptionalMethods.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.optional; 2 | 3 | import pl.piomin.java.samples.records.Person; 4 | 5 | import java.util.NoSuchElementException; 6 | import java.util.Optional; 7 | 8 | public class OptionalMethods { 9 | 10 | private PersonRepository repository = new PersonRepository(); 11 | 12 | public Person getPersonById(Long id) { 13 | Optional personOpt = repository.findById(id); 14 | return personOpt.orElseThrow(); 15 | } 16 | 17 | public Person getPersonByIdOldWay(Long id) { 18 | Optional personOpt = repository.findById(id); 19 | if (personOpt.isPresent()) 20 | return personOpt.get(); 21 | else 22 | throw new NoSuchElementException(); 23 | } 24 | 25 | public void printPersonById(Long id) { 26 | Optional personOpt = repository.findById(id); 27 | personOpt.ifPresentOrElse( 28 | System.out::println, 29 | () -> System.out.println("Person not found") 30 | ); 31 | } 32 | 33 | public void printPersonByIdOldWay(Long id) { 34 | Optional personOpt = repository.findById(id); 35 | if (personOpt.isPresent()) 36 | System.out.println(personOpt.get()); 37 | else 38 | System.out.println("Person not found"); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/pl/piomin/java/samples/structuredconcurrency/StructuredConcurrencyTests.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.structuredconcurrency; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.concurrent.ExecutionException; 6 | import java.util.concurrent.StructuredTaskScope; 7 | import java.util.function.Supplier; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertNotNull; 10 | 11 | public class StructuredConcurrencyTests { 12 | 13 | @Test 14 | void shouldFinish() throws InterruptedException, ExecutionException { 15 | try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { 16 | Supplier user = scope.fork(this::findUser); 17 | Supplier order = scope.fork(this::fetchOrder); 18 | 19 | scope.join().throwIfFailed(); 20 | 21 | Response r = new Response(user.get(), order.get()); 22 | assertNotNull(r.getUser()); 23 | assertNotNull(r.getOrder()); 24 | } 25 | } 26 | 27 | private String findUser() { 28 | return "user1"; 29 | } 30 | 31 | private Integer fetchOrder() { 32 | return 100; 33 | } 34 | 35 | class Response { 36 | String user; 37 | Integer order; 38 | 39 | public Response(String user, Integer order) { 40 | this.user = user; 41 | this.order = order; 42 | } 43 | 44 | public String getUser() { 45 | return user; 46 | } 47 | 48 | public Integer getOrder() { 49 | return order; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/pl/piomin/java/samples/collections/SequencedCollectionTests.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.collections; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedHashSet; 7 | import java.util.SequencedCollection; 8 | import java.util.SequencedSet; 9 | 10 | import static org.junit.jupiter.api.Assertions.assertEquals; 11 | 12 | public class SequencedCollectionTests { 13 | 14 | @Test 15 | void shouldCallSet() { 16 | SequencedSet s = new LinkedHashSet<>(); 17 | s.add(0); 18 | s.add(9); 19 | System.out.println(s); 20 | assertEquals(s.getFirst(), 0); 21 | assertEquals(s.getLast(), 9); 22 | s.addFirst(5); 23 | s.addLast(10); 24 | System.out.println(s); 25 | assertEquals(s.getFirst(), 5); 26 | assertEquals(s.getLast(), 10); 27 | s.removeFirst(); 28 | s.removeLast(); 29 | assertEquals(s.getFirst(), 0); 30 | assertEquals(s.getLast(), 9); 31 | s = s.reversed(); 32 | System.out.println(s); 33 | assertEquals(s.getFirst(), 9); 34 | assertEquals(s.getLast(), 0); 35 | } 36 | 37 | @Test 38 | void shouldCallList() { 39 | SequencedCollection s = new ArrayList<>(); 40 | s.add(0); 41 | s.add(9); 42 | System.out.println(s); 43 | assertEquals(s.getFirst(), 0); 44 | assertEquals(s.getLast(), 9); 45 | s.addFirst(5); 46 | s.addLast(10); 47 | System.out.println(s); 48 | assertEquals(s.getFirst(), 5); 49 | assertEquals(s.getLast(), 10); 50 | s.removeFirst(); 51 | s.removeLast(); 52 | assertEquals(s.getFirst(), 0); 53 | assertEquals(s.getLast(), 9); 54 | s = s.reversed(); 55 | System.out.println(s); 56 | assertEquals(s.getFirst(), 9); 57 | assertEquals(s.getLast(), 0); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/pl/piomin/java/samples/switches/SwitchComparison.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.switches; 2 | 3 | import pl.piomin.java.samples.sealedclasses.Cat; 4 | import pl.piomin.java.samples.sealedclasses.Dog; 5 | import pl.piomin.java.samples.sealedclasses.Pet; 6 | 7 | public class SwitchComparison { 8 | 9 | public String oldSwitch(int number) { 10 | switch (number) { 11 | case 1: 12 | return "one"; 13 | case 2: 14 | return "two"; 15 | case 3: 16 | return "three"; 17 | default: 18 | return "other"; 19 | } 20 | } 21 | 22 | public String newSwitch(int number) { 23 | return switch (number) { 24 | case 1 -> "one"; 25 | case 2 -> "two"; 26 | case 3 -> "three"; 27 | default -> "other"; 28 | }; 29 | } 30 | 31 | public String oldMultiSwitch(int day) { 32 | switch (day) { 33 | case 1: 34 | case 2: 35 | case 3: 36 | case 4: 37 | case 5: 38 | return "workday"; 39 | case 6: 40 | case 7: 41 | return "weekend"; 42 | default: 43 | return "invalid"; 44 | } 45 | } 46 | 47 | public String newMultiSwitch(int day) { 48 | return switch (day) { 49 | case 1, 2, 3, 4, 5 -> "workday"; 50 | case 6, 7 -> "weekend"; 51 | default -> "invalid"; 52 | }; 53 | } 54 | 55 | public String oldSwitchWithBreak(int number) { 56 | String word = "other"; 57 | switch (number) { 58 | case 1: 59 | word = "one"; 60 | break; 61 | case 2: 62 | word = "two"; 63 | break; 64 | case 3: 65 | word = "three"; 66 | break; 67 | } 68 | return word; 69 | } 70 | 71 | public String newSwitchWithPatternMatching(Pet pet) { 72 | return switch (pet) { 73 | case Cat c -> "cat"; 74 | case Dog d -> "dog"; 75 | default -> "other pet"; 76 | }; 77 | } 78 | 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/pl/piomin/java/samples/unmodifiablecollections/CollectionsCreatorTest.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.unmodifiablecollections; 2 | 3 | import org.eclipse.collections.api.factory.Lists; 4 | import org.eclipse.collections.api.list.ImmutableList; 5 | import org.eclipse.collections.api.list.MutableList; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.Test; 8 | import pl.piomin.java.samples.helper.Employee; 9 | import pl.piomin.java.samples.helper.Organization; 10 | import pl.piomin.java.samples.records.Person; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | import java.util.stream.Collectors; 15 | import java.util.stream.Stream; 16 | 17 | public class CollectionsCreatorTest { 18 | 19 | @Test 20 | void listFormArray() { 21 | List list = Arrays.asList("A", "B", "C"); 22 | Assertions.assertThrows(UnsupportedOperationException.class, () -> list.add("D")); 23 | } 24 | 25 | @Test 26 | void unmodifiableList() { 27 | List list = List.of("A", "B", "C"); 28 | Assertions.assertThrows(UnsupportedOperationException.class, () -> list.add("D")); 29 | } 30 | 31 | @Test 32 | void unmodifiableList2() { 33 | ImmutableList list = Lists.immutable.of("A", "B", "C"); 34 | Assertions.assertEquals(3, list.size()); 35 | } 36 | 37 | @Test 38 | void select() { 39 | Employee e1 = new Employee(1, "Test1", "Developer"); 40 | Employee e2 = new Employee(2, "Test2", "Developer"); 41 | Employee e3 = new Employee(3, "Test3", "Developer"); 42 | Employee e4 = new Employee(4, "Test4", "Developer"); 43 | Organization o1 = new Organization("Test1", List.of(e1, e2)); 44 | Organization o2 = new Organization("Test2", List.of(e3, e4)); 45 | MutableList organizations = Lists.mutable.of(o1, o2); 46 | MutableList> employees = organizations 47 | .select(o -> o.name().equals("Test1")) 48 | .collect(Organization::employees); 49 | Assertions.assertEquals(2, employees.getFirst().size()); 50 | } 51 | 52 | @Test 53 | void selectStreams() { 54 | Employee e1 = new Employee(1, "Test1", "Developer"); 55 | Employee e2 = new Employee(2, "Test2", "Developer"); 56 | Employee e3 = new Employee(3, "Test3", "Developer"); 57 | Employee e4 = new Employee(4, "Test4", "Developer"); 58 | Organization o1 = new Organization("Test1", List.of(e1, e2)); 59 | Organization o2 = new Organization("Test2", List.of(e3, e4)); 60 | List organizations = List.of(o1, o2); 61 | List> employees = organizations 62 | .stream() 63 | .filter(o -> o.name().equals("Test1")) 64 | .map(Organization::employees) 65 | .collect(Collectors.toList()); 66 | Assertions.assertEquals(2, employees.get(0).size()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | pl.piomin.samples 8 | sample-java-new-features 9 | 1.0-SNAPSHOT 10 | 11 | 12 | ${java.version} 13 | ${java.version} 14 | 21 15 | piomin_sample-java-new-features 16 | piomin 17 | https://sonarcloud.io 18 | 19 | 20 | 21 | 22 | org.eclipse.collections 23 | eclipse-collections 24 | 13.0.0 25 | 26 | 27 | org.mapstruct 28 | mapstruct 29 | 1.6.3 30 | 31 | 32 | org.projectlombok 33 | lombok 34 | 1.18.42 35 | 36 | 37 | org.junit.jupiter 38 | junit-jupiter 39 | 6.0.1 40 | 41 | 42 | 43 | 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-compiler-plugin 48 | 3.14.1 49 | 50 | ${maven.compiler.source} 51 | 52 | --enable-preview 53 | 54 | ${maven.compiler.source} 55 | ${maven.compiler.target} 56 | 57 | 58 | org.mapstruct 59 | mapstruct-processor 60 | 1.6.3 61 | 62 | 63 | org.projectlombok 64 | lombok 65 | 1.18.42 66 | 67 | 68 | org.projectlombok 69 | lombok-mapstruct-binding 70 | 0.2.0 71 | 72 | 73 | 74 | 75 | 76 | org.apache.maven.plugins 77 | maven-surefire-plugin 78 | 3.5.4 79 | 80 | --enable-preview 81 | 82 | 83 | 84 | org.jacoco 85 | jacoco-maven-plugin 86 | 0.8.14 87 | 88 | 89 | 90 | prepare-agent 91 | 92 | 93 | 94 | report 95 | test 96 | 97 | report 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/test/java/pl/piomin/java/samples/unmodifiablecollections/EclipseCollectionsTest.java: -------------------------------------------------------------------------------- 1 | package pl.piomin.java.samples.unmodifiablecollections; 2 | 3 | import org.eclipse.collections.api.block.procedure.Procedure; 4 | import org.eclipse.collections.api.factory.Lists; 5 | import org.eclipse.collections.api.list.MutableList; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.Test; 8 | import pl.piomin.java.samples.helper.Employee; 9 | import pl.piomin.java.samples.helper.Organization; 10 | import pl.piomin.java.samples.records.PersonOld; 11 | 12 | import java.util.Comparator; 13 | import java.util.List; 14 | import java.util.NoSuchElementException; 15 | import java.util.stream.Collectors; 16 | 17 | public class EclipseCollectionsTest { 18 | 19 | @Test 20 | void collectFlatEclipseColl() { 21 | Employee e1 = new Employee(1, "Test1", "Developer"); 22 | Employee e2 = new Employee(2, "Test2", "Developer"); 23 | Employee e3 = new Employee(3, "Test3", "Developer"); 24 | Employee e4 = new Employee(4, "Test4", "Developer"); 25 | Organization o1 = new Organization("Test1", List.of(e1, e2)); 26 | Organization o2 = new Organization("Test2", List.of(e3, e4)); 27 | MutableList organizations = Lists.mutable.of(o1, o2); 28 | organizations.flatCollect(Organization::employees); 29 | MutableList employees = organizations 30 | .select(o -> o.name().equals("Test1")) 31 | .flatCollect(Organization::employees); 32 | Assertions.assertEquals(2, employees.size()); 33 | MutableList> employees2 = organizations 34 | .collectIf(o -> o.name().equals("Test1"), Organization::employees); 35 | Assertions.assertEquals(2, employees2.get(0).size()); 36 | } 37 | 38 | @Test 39 | void collectFlatJava8Streams() { 40 | Employee e1 = new Employee(1, "Test1", "Developer"); 41 | Employee e2 = new Employee(2, "Test2", "Developer"); 42 | Employee e3 = new Employee(3, "Test3", "Developer"); 43 | Employee e4 = new Employee(4, "Test4", "Developer"); 44 | Organization o1 = new Organization("Test1", List.of(e1, e2)); 45 | Organization o2 = new Organization("Test2", List.of(e3, e4)); 46 | List organizations = List.of(o1, o2); 47 | List employees = organizations 48 | .stream() 49 | .filter(o -> o.name().equals("Test1")) 50 | .map(Organization::employees) 51 | .flatMap(List::stream) 52 | .collect(Collectors.toList()); 53 | Assertions.assertEquals(2, employees.size()); 54 | 55 | List> employees2 = organizations 56 | .stream() 57 | .filter(o -> o.name().equals("Test1")) 58 | .map(Organization::employees) 59 | .collect(Collectors.toList()); 60 | Assertions.assertEquals(2, employees2.get(0).size()); 61 | } 62 | 63 | @Test 64 | void countEclipseColl() { 65 | Employee e1 = new Employee(1, "Test1", "Developer"); 66 | Employee e2 = new Employee(2, "Test2", "Architect"); 67 | Employee e3 = new Employee(3, "Test3", "Developer"); 68 | Employee e4 = new Employee(4, "Test4", "Tester"); 69 | MutableList employees = Lists.mutable.of(e1, e2, e3, e4); 70 | int c = employees.count(emp -> emp.position().equals("Developer")); 71 | Assertions.assertEquals(2, c); 72 | 73 | Employee r1 = employees.minBy(Employee::id); 74 | Assertions.assertNotNull(r1); 75 | Assertions.assertEquals(1, r1.id()); 76 | } 77 | 78 | @Test 79 | void countJava8Streams() { 80 | Employee e1 = new Employee(1, "Test1", "Developer"); 81 | Employee e2 = new Employee(2, "Test2", "Architect"); 82 | Employee e3 = new Employee(3, "Test3", "Developer"); 83 | Employee e4 = new Employee(4, "Test4", "Tester"); 84 | List employees = List.of(e1, e2, e3, e4); 85 | long c = employees 86 | .stream() 87 | .filter(emp -> emp.position().equals("Developer")) 88 | .count(); 89 | Assertions.assertEquals(2L, c); 90 | 91 | Employee r1 = employees 92 | .stream() 93 | .min(Comparator.comparing(Employee::id)) 94 | .orElseThrow(NoSuchElementException::new); 95 | Assertions.assertEquals(1, r1.id()); 96 | } 97 | 98 | @Test 99 | void lazyEclipseColl() { 100 | PersonOld p1 = new PersonOld("Test1", 20); 101 | PersonOld p2 = new PersonOld("Test2", 18); 102 | PersonOld p3 = new PersonOld("Test3", 24); 103 | PersonOld p4 = new PersonOld("Test4", 30); 104 | PersonOld p5 = new PersonOld("Test5", 35); 105 | MutableList persons = Lists.mutable.with(p1, p2, p3, p4, p5); 106 | persons 107 | .asLazy() 108 | .tap(p -> p.setAge(p.getAge() + 2)) 109 | .select(p -> p.getAge() > 20) 110 | .getFirst(); 111 | 112 | System.out.println("---"); 113 | 114 | persons 115 | .distinct() 116 | .tap(p -> p.setAge(p.getAge() + 2)) 117 | .select(p -> p.getAge() > 20) 118 | .getFirst(); 119 | 120 | System.out.println("---"); 121 | 122 | List ps = List.of(p1, p2, p3, p4, p5); 123 | ps.stream() 124 | .filter(p -> p.getAge() > 20) 125 | .findFirst() 126 | .orElseThrow(); 127 | } 128 | } 129 | --------------------------------------------------------------------------------