/100DaysOfJava

A little of Java content every day for a hundred days.

Primary LanguageJavaApache License 2.0Apache-2.0

100 Days of Java

A little of Java content every day for a hundred days.

If you have any questions, ask me on my social media.

Day 1 - Generating a random number within a specific range.

import java.security.SecureRandom;

public final class Day001 {

    public static final SecureRandom SECURE_RANDOM = new SecureRandom();

    public static void main(String[] args) {
        System.out.println("Generating a number between 50 and 100...");
        System.out.println(randomNumberBetween(50, 100));
    }

    private static int randomNumberBetween(int minimum, int maximum) {
        return SECURE_RANDOM.nextInt(maximum - minimum) + minimum;
    }

}

Day 2 - Formatting a LocalDateTime object.

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public final class Day002 {

    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");

    public static void main(String[] args) {
        LocalDateTime currentDateTime = LocalDateTime.now();
        String formattedDateTime = currentDateTime.format(FORMATTER);
        System.out.println(formattedDateTime);
    }

}

Day 3 - Scheduling a task to run every 2 seconds.

import java.time.LocalTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Day003 {

    private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

    public static void main(String[] args) throws InterruptedException {
        var day003 = new Day003();
        day003.printCurrentTimeEvery2Seconds();
        Thread.sleep(15_000);
        day003.stopPrinting();
    }

    public void printCurrentTimeEvery2Seconds() {
        Runnable task = () -> System.out.println(LocalTime.now());
        scheduledExecutorService.scheduleAtFixedRate(task, 0, 2, TimeUnit.SECONDS);
    }

    public void stopPrinting() {
        scheduledExecutorService.shutdown();
    }

}

Day 4 - Removing items from a List.

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class Day004 {

    public static void main(String[] args) {
        List<Person> beatles = new ArrayList<>();
        beatles.add(new Person("1", "John Lennon", LocalDate.of(1940, 10, 9)));
        beatles.add(new Person("2", "Paul McCartney", LocalDate.of(1942, 6, 18)));
        beatles.add(new Person("3", "George Harrison", LocalDate.of(1943, 2, 25)));
        beatles.add(new Person("4", "Ringo Starr", LocalDate.of(1940, 7, 7)));

        removeItemUsingEquals(beatles);

        removeItemUsingAnSpecificFilter(beatles);

        System.out.println(beatles);
    }

    private static void removeItemUsingAnSpecificFilter(List<Person> beatles) {
        beatles.removeIf(person -> "George Harrison".equals(person.getName()));
    }

    private static void removeItemUsingEquals(List<Person> beatles) {
        var lennon = new Person("1", "John Lennon", LocalDate.of(1940, 10, 9));
        beatles.remove(lennon);
    }

    static class Person {

        private final String id;

        private final String name;

        private final LocalDate dateOfBirth;

        Person(String id, String name, LocalDate dateOfBirth) {
            this.id = id;
            this.name = name;
            this.dateOfBirth = dateOfBirth;
        }

        public String getId() {
            return id;
        }

        public String getName() {
            return name;
        }

        public LocalDate getDateOfBirth() {
            return dateOfBirth;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            var person = (Person) o;
            return Objects.equals(id, person.id) && Objects.equals(name, person.name) && Objects.equals(dateOfBirth, person.dateOfBirth);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, name, dateOfBirth);
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }

}

Day 5 - Creating a list with filtered items from other lists.

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Day005 {

    private static final String GUITAR = "Guitar";
    private static final String DRUMS = "Drums";
    private static final String BASS = "Bass";
    private static final String VOCALS = "Vocals";
    private static final String KEYBOARDS = "Keyboards";

    public static void main(String[] args) {
        List<BandMember> pinkFloyd = List.of(
                new BandMember("David Gilmour", GUITAR),
                new BandMember("Roger Waters", BASS),
                new BandMember("Richard Wright", KEYBOARDS),
                new BandMember("Nick Mason", DRUMS)
        );

        List<BandMember> ironMaiden = List.of(
                new BandMember("Bruce Dickinson", VOCALS),
                new BandMember("Steve Harris", BASS),
                new BandMember("Adrian Smith", GUITAR),
                new BandMember("Dave Murray", GUITAR),
                new BandMember("Nicko McBrain", DRUMS)
        );

        List<BandMember> blackSabbath = List.of(
                new BandMember("Ozzy Osbourne", VOCALS),
                new BandMember("Geezer Butler", BASS),
                new BandMember("Toni Iommi", GUITAR),
                new BandMember("Bill Ward", DRUMS)
        );

        Stream<BandMember> musicians = Stream.concat(Stream.concat(pinkFloyd.stream(), ironMaiden.stream()), blackSabbath.stream());

        List<String> guitarPlayers = musicians.filter(bandMember -> GUITAR.equals(bandMember.instrument))
                                              .map(BandMember::name)
                                              .collect(Collectors.toList());

        System.out.println(guitarPlayers);
    }

    static record BandMember(String name, String instrument) {
    }
}

Day 6 - Running a task asynchronously.

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ForkJoinPool;
import java.util.logging.Level;
import java.util.logging.Logger;

import static java.util.concurrent.TimeUnit.SECONDS;

public class Day006 {

    private static final Logger LOGGER = Logger.getLogger(Day006.class.getName());

    public static void main(String[] args) {
        CompletableFuture.runAsync(Day006::task);

        LOGGER.info("Message from the main thread. Note that this message is logged before the async task ends.");

        LOGGER.info("Waiting for the async task to end.");
        boolean isQuiecent = ForkJoinPool.commonPool().awaitQuiescence(5, SECONDS);
        if (isQuiecent) {
            LOGGER.info("Async task ended.");
        } else {
            LOGGER.log(Level.SEVERE, "The async task is taking too long to finish. This program will end anyway.");
        }
    }

    private static void task() {
        LOGGER.info("Async task starting. This message is logged by the async task thread");
        try {
            Thread.sleep(1000);
            LOGGER.info("Async task is ending. This message is logged by the async task thread");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            LOGGER.log(Level.SEVERE, "The async task thread was interrupted.", e);
        }
    }
}

Day 7 - Formatting a message using MessageFormat.

import java.text.MessageFormat;

public class Day007 {

    public static void main(String[] args) {
        showMessage("Java", "is", "great");
    }

    private static void showMessage(String param1, String param2, String param3) {
        String message = MessageFormat.format("This message contains 3 parameters. The #1 is ''{0}'', the #2 is ''{1}'', and the #3 is ''{2}''.",
                param1, param2, param3);
        System.out.println(message);
    }
}

Day 8 - Creating a thread pool to run tasks simultaneously and reuse threads.

import java.security.SecureRandom;
import java.text.MessageFormat;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Logger;

public class Day008 {

    private static final Logger LOGGER = Logger.getLogger(Day008.class.getName());

    private static final SecureRandom RANDOM = new SecureRandom();

    public static void main(String[] args) {
        LOGGER.info("Creating a thread pool with 5 threads");
        ExecutorService executor = Executors.newFixedThreadPool(5);

        /*
         * Will submit 15 tasks. Note that there's only 5 threads to run all of them in our thread pool.
         * So the first 5 tasks will run simultaneously and 10 tasks will wait in the queue until a thread is available.
         */
        LOGGER.info("Starting tasks submissions.");
        try {
            for (var i = 1; i <= 15; i++) {
                int taskId = i;
                LOGGER.info(() -> MessageFormat.format("Will submit task {0}.", taskId));
                executor.submit(() -> task(taskId));
            }
        } finally {
            executor.shutdown();
        }
    }

    private static void task(int taskId) {
        LOGGER.info(() -> MessageFormat.format("Running task {0}.", taskId));
        simulateLongProcessing();
        LOGGER.info(() -> MessageFormat.format("Task {0} has finished.", taskId));
    }

    private static void simulateLongProcessing() {
        try {
            Thread.sleep((RANDOM.nextInt(3) + 10) * 1000L);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException(MessageFormat.format("Thread {0} was interrupted.", Thread.currentThread().getName()), e);
        }
    }
}

Day 9 - Creating a valued Enum.

public class Day009 {

    public static void main(String[] args) {
        for (Gender gender : Gender.values()) {
            System.out.printf("The value of %s is %s%n", gender, gender.getValue());
        }
    }

    public enum Gender {
        FEMALE('f'),
        MALE('m');

        private final char value;

        Gender(char value) {
            this.value = value;
        }

        public char getValue() {
            return value;
        }
    }
}

Day 10 - Using Google’s Jimfs to write tests that use an in-memory file system.

import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.nio.file.*;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;

class Day010Test {

    @Test
    void fileDoesNotExist() {
        FileSystem fileSystem = Jimfs.newFileSystem(Configuration.unix());
        Path directory = fileSystem.getPath("/directory");
        Path file = directory.resolve(fileSystem.getPath("myfile.txt"));

        assertThatCode(() -> Files.write(file, "thegreatapi.com".getBytes(), StandardOpenOption.WRITE))
                .isInstanceOf(NoSuchFileException.class);
    }

    @Test
    void fileExists() throws IOException {
        FileSystem fileSystem = Jimfs.newFileSystem(Configuration.unix());
        Path directory = fileSystem.getPath("/directory");
        Path file = directory.resolve(fileSystem.getPath("myfile.txt"));

        Files.createDirectory(directory);
        Files.createFile(file);

        assertThatCode(() -> Files.write(file, "thegreatapi.com".getBytes(), StandardOpenOption.WRITE))
                .doesNotThrowAnyException();

        assertThat(Files.readString(file))
                .isEqualTo("thegreatapi.com");
    }
}

Day 11 - Sorting a java.util.Map by its values.

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;

public class Day011 {

    public static void main(String[] args) {
        Map<String, Integer> unsortedMap = Map.of(
                "three", 3,
                "one", 1,
                "four", 4,
                "five", 5,
                "two", 2
        );

        Map<String, Integer> sortedMap = sortByValue(unsortedMap);

        System.out.println(sortedMap);
    }

    private static Map<String, Integer> sortByValue(Map<String, Integer> unsortedMap) {
        TreeMap<Integer, String> treeMap = new TreeMap<>();
        unsortedMap.forEach((key, value) -> treeMap.put(value, key));

        Map<String, Integer> sortedMap = new LinkedHashMap<>();
        treeMap.forEach((key, value) -> sortedMap.put(value, key));

        return Collections.unmodifiableMap(sortedMap);
    }
}

Day 12 - Using Callable and Future to run tasks in parallel.

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Logger;

public class Day012 {

    private static final Logger LOGGER = Logger.getLogger(Day012.class.getName());

    public static void main(String[] args) throws InterruptedException {
        var executorService = Executors.newSingleThreadExecutor();

        try {
            Callable<Integer> callable = Day012::doALongCalculation;
            Future<Integer> future = executorService.submit(callable);

            doOtherThingWhileCalculating();

            LOGGER.info("Will get the calculated value. Note that the value will be get immediately");
            LOGGER.info("Calculated value: " + future.get());
        } catch (ExecutionException e) {
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
    }

    private static int doALongCalculation() throws InterruptedException {
        Thread.sleep(5000L);
        return 42;
    }

    private static void doOtherThingWhileCalculating() throws InterruptedException {
        Thread.sleep(7000L);
    }
}

Day 13 - Creating a lazily initialized Singleton.

import java.time.LocalDateTime;

public final class MySingletonClass {

    private final LocalDateTime creationDateTime;

    private MySingletonClass(LocalDateTime creationDateTime) {
        this.creationDateTime = creationDateTime;
    }

    public LocalDateTime getCreationDateTime() {
        return creationDateTime;
    }

    public static MySingletonClass getInstance() {
        return InstanceHolder.INSTANCE;
    }

    private static final class InstanceHolder {
        static final MySingletonClass INSTANCE = new MySingletonClass(LocalDateTime.now());
    }
}

Day 14 - Never pass a double as argument when constructing BigDecimal objects.

import java.math.BigDecimal;

public class Day014 {

    public static void main(String[] args) {
        // Prints 1.229999999999999982236431605997495353221893310546875
        System.out.println(new BigDecimal(1.23));

        // Prints 1.23
        System.out.println(new BigDecimal("1.23"));

        // Prints 1.23
        System.out.println(BigDecimal.valueOf(1.23));
    }
}

Day 15 - Builder Pattern

import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

public class Day015 {

    public static void main(String[] args) {
        Person john = Person.builder()
                            .name("John")
                            .children(List.of(
                                    Person.builder()
                                          .name("Amanda")
                                          .petName("Toto")
                                          .build()
                            ))
                            .build();

        System.out.println(john);
    }

    public static class Person {

        private final String name;

        private final List<Person> children;

        @Nullable
        private final String petName;

        private Person(Builder builder) {
            name = Objects.requireNonNull(builder.name);
            children = builder.children != null ? builder.children : List.of();
            petName = builder.petName;
        }

        public String getName() {
            return name;
        }

        public List<Person> getChildren() {
            return children;
        }

        @Nullable
        public String getPetName() {
            return petName;
        }

        public static Builder builder() {
            return new Builder();
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", children=" + children +
                    ", petName='" + petName + '\'' +
                    '}';
        }
    }

    public static final class Builder {

        private String name;

        private List<Person> children;

        @Nullable
        private String petName;

        private Builder() {
        }

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Builder children(List<Person> children) {
            this.children = Collections.unmodifiableList(children);
            return this;
        }

        public Builder petName(String petName) {
            this.petName = petName;
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }
}

Day 16 - Joining Strings.

public class Day016 {

    public static void main(String[] args) {
        System.out.println(createSql("id", "name", "coutry", "gender"));
    }

    private static String createSql(String... columns) {
        return new StringBuilder("SELECT ")
                .append(String.join(", ", columns))
                .append(" FROM PEOPLE")
                .toString();
    }
}

Day 17 - Splitting Strings.

import java.util.regex.Pattern;

public class Day017 {

    private static final Pattern REGEX = Pattern.compile(", ");

    public static void main(String[] args) {
        System.out.println("Simple split: ");
        for (String column : simpleSplit()) {
            System.out.println(column);
        }

        System.out.println("Performant split: ");
        for (String column : performantSplit()) {
            System.out.println(column);
        }
    }

    private static String[] simpleSplit() {
        return "id, name, country, gender".split(", ");
    }

    // If you will split frequently, prefer this implementation.
    private static String[] performantSplit() {
        return REGEX.split("id, name, country, gender");
    }
}

Day 18 - Finding the maximum value from a Collection.

import java.util.Collection;
import java.util.List;
import java.util.NoSuchElementException;

public class Day018 {

    public static void main(String[] args) {
        System.out.println(max(List.of(6, 3, 1, 8, 3, 9, 2, 7)));
    }

    private static Integer max(Collection<Integer> collection) {
        return collection.stream()
                         .max(Integer::compareTo)
                         .orElseThrow(NoSuchElementException::new);
    }
}

Day 19 - A Map implementation that keeps the elements in the same order that they were inserted.

import java.util.LinkedHashMap;
import java.util.Map;

public class Day019 {

    public static void main(String[] args) {
        Map<Integer, String> map = new LinkedHashMap<>();

        map.put(5, "five");
        map.put(4, "four");
        map.put(3, "three");
        map.put(2, "two");
        map.put(1, "one");

        map.forEach((key, value) -> System.out.println(key + ": " + value));
    }
}

Day 20 - Reversing a String

public class Day020 {

    public static void main(String[] args) {
        var original = "moc.ipataergeht";
        var reversed = new StringBuilder(original).reverse().toString();
        System.out.println(reversed);
    }
}

Day 21 - Using WireMock to mock a web server.

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.ok;
import static org.junit.jupiter.api.Assertions.assertEquals;

class Day021Test {

    private WireMockServer server;

    @BeforeEach
    void setUp() {
        server = new WireMockServer(WireMockConfiguration.wireMockConfig().dynamicPort());
        server.start();
    }

    @Test
    void test() throws Exception {
        mockWebServer();

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                                         .uri(URI.create("http://localhost:" + server.port() + "/my/resource"))
                                         .build();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        assertEquals("TheGreatAPI.com", response.body());
    }

    private void mockWebServer() {
        server.stubFor(get("/my/resource")
                .willReturn(ok()
                        .withBody("TheGreatAPI.com")));
    }

    @AfterEach
    void tearDown() {
        server.shutdownServer();
    }
}

Day 22 - Mapping and reducing from a List.

import java.util.List;

public class Day022 {

    public static void main(String[] args) {
        List<Order> orders = readOrders();

        String bands = orders.stream()
                             .map(Order::customer)
                             .map(Customer::band)
                             .reduce((band1, band2) -> String.join(";", band1, band2))
                             .orElse("None");

        System.out.println(bands);
        /* Prints:
        Pink Floyd;Black Sabbath;Ozzy Osbourne
         */
    }

    private static List<Order> readOrders() {
        var gilmour = new Customer("David Gilmour", "Pink Floyd");
        var iommi = new Customer("Toni Iommi", "Black Sabbath");
        var rhoads = new Customer("Randy Rhoads", "Ozzy Osbourne");

        var strato = new Product("Fender", "Stratocaster");
        var sg = new Product("Gibson", "SG");
        var lesPaul = new Product("Gibson", "Les Paul");
        var rr = new Product("Jackson", "RR");

        return List.of(
                new Order(gilmour, List.of(strato)),
                new Order(iommi, List.of(sg)),
                new Order(rhoads, List.of(lesPaul, rr))
        );
    }

    static record Customer(String name, String band) {
    }

    static record Product(String brand, String modelName) {
    }

    static record Order(Customer customer, List<Product> products) {
    }
}

Day 23 - Loading properties from a file.

import java.io.IOException;
import java.util.Properties;

public class Day023 {

    public static void main(String[] args) throws IOException {
        var properties = new Properties();
        try (var reader = Day023.class.getClassLoader().getResourceAsStream("config.properties")) {
            properties.load(reader);
        }
        System.out.println(properties);
    }
}

Day 24 - Running operating system commands.

package com.thegreatapi.ahundreddaysofjava.day024;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import static java.util.concurrent.TimeUnit.SECONDS;

public class Day024 {

    public static void main(String[] args) throws IOException, InterruptedException {
        var process = new ProcessBuilder("ls").start();
        try (var stdOutReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
             var stdErrReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
            if (process.waitFor(5, SECONDS)) {
                int exitValue = process.exitValue();
                if (exitValue == 0) {
                    stdOutReader.lines().forEach(System.out::println);
                } else {
                    stdErrReader.lines().forEach(System.err::println);
                }
            } else {
                throw new RuntimeException("Timeout");
            }
        }
    }
}

Day 25 - Pattern Matching for instanceof in JDK 16.

public class Day025 {

    public static void main(String[] args) {
        Number n = 6;

        // Instead of doing:
        if (n instanceof Integer) {
            Integer i = (Integer) n;
            print(i);
        }

        // Just do:
        if (n instanceof Integer i) {
            print(i);
        }
    }

    private static void print(Integer i) {
        System.out.println(i);
    }
}

Day 26 - Using Optional when null is a valid return value.

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Optional;

public class Day026 {

    public static void main(String[] args) {
        // Instead of doing:
        String nullableValue = getNullableValue();
        if (nullableValue != null) {
            System.out.println(nullableValue.length());
        } else {
            System.out.println(0);
        }

        // Just do:
        System.out.println(getOptionalValue().map(String::length).orElse(0));
    }

    @Nonnull
    private static Optional<String> getOptionalValue() {
        return Optional.empty();
    }

    @Nullable
    private static String getNullableValue() {
        return null;
    }
}

Day 27 - Printing a List: one item per line.

import java.util.List;

public class Day027 {

    public static void main(String[] args) {
        List<Player> players = createList();

        String message = players.stream()
                                .map(Player::toString)
                                .reduce((p1, p2) -> p1 + System.lineSeparator() + p2)
                                .orElse("");

        System.out.println(message);
    }

    private static List<Player> createList() {
        Player messi = new Player("Lionel Messi", "Barcelona", "Argentina", 42);
        Player cr7 = new Player("Cristiano Ronaldo", "Juventus", "Portugal", 50);
        Player neymar = new Player("Neymar Jr.", "PSG", "Brazil", 41);

        return List.of(messi, cr7, neymar);
    }

    private record Player(String name, String club, String coutry, int numberOfGoals) {
    }
}

Day 28 - Sorting a List by a specific attribute.

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class Day028 {

    public static void main(String[] args) {
        Player messi = new Player("Lionel Messi", "Barcelona", "Argentina", 42);
        Player cr7 = new Player("Cristiano Ronaldo", "Juventus", "Portugal", 50);
        Player neymar = new Player("Neymar Jr.", "PSG", "Brazil", 41);

        List<Player> players = Arrays.asList(messi, cr7, neymar);

        players.sort(Comparator.comparing(Player::numberOfGoals).reversed());

        System.out.println("Top Scorers:");
        players.forEach(System.out::println);
    }

    private record Player(String name, String club, String coutry, int numberOfGoals) {
    }
}