- Day 1 - Generating a random number within a specific range.
- Day 2 - Formatting a
LocalDateTime
object. - Day 3 - Scheduling a task to run every 2 seconds.
- Day 4 - Removing items from a List.
- Day 5 - Creating a list with filtered items from other lists.
- Day 6 - Running a task asynchronously.
- Day 7 - Formatting a message using
MessageFormat
. - Day 8 - Creating a thread pool to run tasks simultaneously and reuse threads.
- Day 9 - Creating a valued Enum.
- Day 10 - Using Google’s Jimfs to write tests that use an in-memory file system.
- Day 11 - Sorting a
java.util.Map
by its values. - Day 12 - Using
Callable
andFuture
to run tasks in parallel. - Day 13 - Creating a lazily initialized Singleton.
- Day 14 - Never pass a
double
as argument when constructingBigDecimal
objects. - Day 15 - Builder Pattern
- Day 16 - Joining Strings.
- Day 17 - Splitting Strings.
- Day 18 - Finding the maximum value from a
Collection
. - Day 19 - A
Map
implementation that keeps the elements in the same order that they were inserted. - Day 20 - Reversing a
String
- Day 21 - Using WireMock to mock a web server.
- Day 22 - Mapping and reducing from a
List
. - Day 23 - Loading properties from a file.
- Day 24 - Running operating system commands.
- Day 25 - Pattern Matching for
instanceof
in JDK 16. - Day 26 - Using
Optional
whennull
is a valid return value. - Day 27 - Printing a
List
: one item per line. - Day 28 - Sorting a
List
by a specific attribute. - Day 29 - Using Awaitility to wait for a task to finish.
- Day 30 - Creating multi-line Strings.
- Day 31 - Converting a
Stream
toList
on JDK 16. - Day 32 - Using switch to return a value.
- Day 33 - Start using
Optional#orElseThrow
instead ofOptional#get
. - Day 34 - Printing information about all java processes running on the machine.
- Day 35 - Autoclosing resources (try-with-resources).
- Day 36 - Using
javax.annotation.Nonnull
(JSR 305) to avoidNullPointerException
. - Day 37 - Using
Objects.requireNonNullElse
whenOptional
is not an option. - Day 38 - Supplying a default value in case of timeout when running an async task.
- Day 39 - Understanding the Prefix (i) and Postfix (i) Operators
- Day 40 - Filtering a Stream using
Predicate#not
. - Day 41 - Quiz about
Collections#unmodifiableList
. - Day 42 - Using
jinfo
to update manageable VM flags at runtime. - Day 43 - Indenting a String.
- Day 44 - Formatting Strings with
java.lang.String#formatted
. - Day 45 - Using
java.util.Comparator#comparing
to sort aList
. - Day 46 - Using
Function
to map a List from one type to another. - Day 47 - Creating a
FunctionalInterface
. - Day 48 - Don’t Repeat Yourself: Reusing functions with
Function#andThen
. - Day 49 -
Function#identity
: Creating a function that always returns its input argument. - Day 50 - Creating a
Stream
from a range of Integers. - Day 51 - Using
UnaryOperator
. - Day 52 - Making
IOException
unchecked. - Day 53 - Using
Supplier
to run an expensive object creation only when and if needed - Day 54 - Computing
Map
values if absent. - Day 55 - Creating smart and readable assertions with AssertJ
- Day 56 - Printing colored characters on the console
- Day 57 - Using Picocli to parse command line arguments
- Day 58 - Never write code that depends on
toString()
format - Day 59 - Using a
Predicate
. - Day 60 - Chaining Predicates.
- Day 61 - Using
var
: Good practices, advices and warnings from Stuart Marks - Day 62 - Converting JSON to Object and Object to JSON using Jakarta JSON Binding (JSON-B).
- Day 63 - Using MicroProfile Fault Tolerance to create a fallback method.
- Day 64 - Partitioning a
Stream
by aPredicate
- Day 65 - Reducing Verbosity of Generics With Diamond Operators
- Day 66 - Replacing Lombok With Pure Java
- Day 67 - Use EnumMap When the Key of Your Map Is an Enum
- Day 68 - Using
StackWalker
from JDK 9 to find aClass
on Stack Trace - Day 69 - Generating an infinite
Stream
. - Day 70 - Creating Parameterized Tests With JUnit.
- Day 71 - Using CDI in a standalone application with Weld.
- Day 72 - Using the CDI annotation
@Named
. - Day 73 - Using CDI Qualifiers.
- Day 74 - Using
java.util.function.Consumer
. - Day 75 - Declaring specific Producers for CDI Beans.
- Day 76 - Creating a REST server with JAX-RS (and Quarkus as runtime)
- Day 77 - A YouTube channel with several presentations from Java Champions and Open Source Developers
- Day 78 - Creating a generic
Function
. - Day 79 - Using the Factory Pattern to Encapsulate Implementations
- Day 80 - Using Sealed Classes from JDK 17
- Day 81 - Finding the frequency of an element in a
List
- Day 82 - Always cast Math operands before assignment
- Day 83 - Using MicroProfile Fault Tolerance to set timeouts on endpoints.
- Day 84 - Using MicroProfile Fault Tolerance to set Retries on endpoints.
- Day 85 - Using MicroProfile Fault Tolerance to set Retries on endpoints for specific Exceptions.
- Day 86 - Using the Delegation Pattern to write decoupled and testable code.
- Day 87 - Verifying if a class is annotated by a particular annotation.
- Day 88 - Verifying if a field is annotated by a particular annotation.
A little of Java content every day for a hundred days.
If you have any questions, ask me on my social media.
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;
}
}
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);
}
}
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();
}
}
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 + '\'' +
'}';
}
}
}
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) {
}
}
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);
}
}
}
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);
}
}
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);
}
}
}
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;
}
}
}
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");
}
}
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);
}
}
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);
}
}
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());
}
}
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));
}
}
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);
}
}
}
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();
}
}
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");
}
}
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);
}
}
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));
}
}
public class Day020 {
public static void main(String[] args) {
var original = "moc.ipataergeht";
var reversed = new StringBuilder(original).reverse().toString();
System.out.println(reversed);
}
}
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();
}
}
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) {
}
}
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);
}
}
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");
}
}
}
}
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);
}
}
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;
}
}
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) {
}
}
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) {
}
}
Day 29 - Using Awaitility to wait for a task to finish.
package com.thegreatapi.ahundreddaysofjava.day029;
import org.junit.jupiter.api.Test;
import java.util.concurrent.CompletableFuture;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
class Day029Test {
@Test
void test() {
Day029 day029 = new Day029();
CompletableFuture.runAsync(day029::startComputingPrimes);
// Await until the already computed primes contain the key 100_000
await().until(() -> day029.getAlreadyComputedPrimes().containsKey(100_000));
assertEquals(1299709, day029.getAlreadyComputedPrimes().get(100_000));
}
}
package com.thegreatapi.ahundreddaysofjava.day029;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.IntStream;
public class Day029 {
private final Map<Integer, Integer> primes = new ConcurrentHashMap<>();
public void startComputingPrimes() {
var count = 0;
for (var i = 2; i <= Integer.MAX_VALUE; i++) {
if (isPrime(i)) {
primes.put(++count, i);
}
}
}
private static boolean isPrime(int number) {
return IntStream.rangeClosed(2, (int) Math.sqrt(number))
.allMatch(n -> number % n != 0);
}
public Map<Integer, Integer> getAlreadyComputedPrimes() {
return Collections.unmodifiableMap(primes);
}
}
public class Day030 {
public static void main(String[] args) {
// Requires JDK 15 or JDK 13 with Preview Features enabled
var myString = """
This is a
text block of
multiple lines.
""";
System.out.println(myString);
var myIndentedString = """
And this is
a text block with
indentation:
public String getMessage() {
if (LocalTime.now().isAfter(LocalTime.of(12, 0))) {
return "Good afternoon";
} else {
return "Good morning";
}
}
""";
System.out.println(myIndentedString);
}
}
package com.thegreatapi.ahundreddaysofjava.day031;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Day031 {
public static void main(String[] args) {
// Instead of doing:
List<String> list = Stream.of("the", "great", "api", ".com")
.collect(Collectors.toList());
// Just do:
List<String> listJdk16 = Stream.of("the", "great", "api", ".com")
.toList();
}
}
package com.thegreatapi.ahundreddaysofjava.day032;
import java.security.SecureRandom;
public class Day032 {
public static void main(String[] args) {
String result = map(randomNumber());
System.out.println(result);
}
private static String map(int number) {
// Requires JDK 12
return switch (number) {
case 1 -> "one";
case 2 -> "two";
case 3 -> "three";
default -> "unknown";
};
}
private static int randomNumber() {
return new SecureRandom().nextInt(4);
}
}
package com.thegreatapi.ahundreddaysofjava.day033;
import java.time.LocalTime;
import java.util.Optional;
public class Day033 {
public static void main(String[] args) {
Optional<LocalTime> optionalValue = getOptionalValue();
// Stop using Optional#get.
// It will be deprecated soon, as you can see in https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8160606
System.out.println(optionalValue.get());
// Start using Optional#orElseThrow instead of Optional#get
System.out.println(getOptionalValue().orElseThrow());
}
private static Optional<LocalTime> getOptionalValue() {
return Optional.of(LocalTime.now());
}
}
package com.thegreatapi.ahundreddaysofjava.day034;
import java.io.File;
public class Day034 {
public static final String JAVA_SUFFIX = File.separator + "java";
public static void main(String[] args) {
ProcessHandle.allProcesses()
.filter(Day034::isJavaProcess)
.map(ProcessHandle::info)
.forEach(System.out::println);
}
private static boolean isJavaProcess(ProcessHandle processHandle) {
return processHandle.info()
.command()
.map(command -> command.endsWith(JAVA_SUFFIX))
.orElse(false);
}
}
package com.thegreatapi.ahundreddaysofjava.day035;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class Day035 {
public static void main(String[] args) throws IOException {
String path = args[0];
// Instead of doing:
var bufferedReader = new BufferedReader(new FileReader(path));
try {
String line = bufferedReader.readLine();
System.out.println(line);
} finally {
bufferedReader.close();
}
// Just do:
try (var autoClosedBufferedReader = new BufferedReader(new FileReader(path))) {
String line = autoClosedBufferedReader.readLine();
System.out.println(line);
}
}
}
package com.thegreatapi.ahundreddaysofjava.day036;
import javax.annotation.Nonnull;
public final class Day036 {
private Day036() {
}
public static void main(String[] args) {
printLenght(null);
}
public static void printLenght(@Nonnull String s) {
System.out.println(s.length());
}
}
package com.thegreatapi.ahundreddaysofjava.day037;
import javax.annotation.Nullable;
import java.util.Objects;
public class Day037 {
public static void main(String[] args) {
String s = Objects.requireNonNullElse(doStuff(), "not found");
// Will print 'not found'
System.out.println(s);
}
@Nullable
private static String doStuff() {
return null;
}
}
package com.thegreatapi.ahundreddaysofjava.day038;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import static java.util.concurrent.TimeUnit.SECONDS;
public class Day038 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
String webSite = CompletableFuture.supplyAsync(Day038::getWebSite)
.completeOnTimeout("https://twitter.com/helber_belmiro", 5, SECONDS)
.get();
System.out.println(webSite);
}
private static String getWebSite() {
try {
Thread.sleep(10_000);
return "thegreatapi.com";
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
}
I did a blog post for that: https://thegreatapi.com/blog/prefix-and-postfix-operators/
package com.thegreatapi.ahundreddaysofjava.day040;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static java.util.function.Predicate.not;
public class Day040 {
public static void main(String[] args) {
// Instead of doing:
printAllThat(word -> !word.isEmpty());
// Just do:
printAllThat(not(String::isEmpty));
}
private static void printAllThat(Predicate<String> filter) {
Stream.of("avocado", "chair", "", "dog", "car")
.filter(filter)
.forEach(System.out::println);
}
}
Given the following:
package com.thegreatapi.ahundreddaysofjava.day041;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Day041 {
public static void main(String[] args) {
List<String> originalList = new ArrayList<>();
originalList.add("one");
originalList.add("two");
originalList.add("three");
List<String> copy = Collections.unmodifiableList(originalList);
originalList.remove("two");
System.out.println(String.join(" ", copy));
}
}
What will be printed?
a) one two tree
b) one three
c) Exception at originalList.remove("two");
d) Exception at String.join(" ", copy)
e) Compilation error
In this article, Vipin Sharma explains how to use the utility jinfo
, which is part of JDK.
It’s pretty useful when you need to set HeapDumpOnOutOfMemoryError to investigate a memory leak, for example.
package com.thegreatapi.ahundreddaysofjava.day043;
public class Day043 {
public static void main(String[] args) {
var methodCode = """
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);
}
}
""";
var classCode = """
public class MyClass {
%s
}
""";
// Requires JDK 12
String fullCode = classCode.formatted(methodCode.indent(4));
System.out.println(fullCode);
}
}
package com.thegreatapi.ahundreddaysofjava.day044;
public class Day044 {
public static final String NAME = "Helber Belmiro";
public static void main(String[] args) {
String formattedString;
// Instead of doing:
formattedString = String.format("My name is %s", NAME);
// Just do: (Requires JDK 15)
formattedString = "My name is %s".formatted(NAME);
System.out.println(formattedString);
}
}
package com.thegreatapi.ahundreddaysofjava.day045;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class Day045 {
public static void main(String[] args) {
List<Musician> queen = getMusicians();
// Instead of doing:
queen.sort(new Comparator<Musician>() {
@Override
public int compare(Musician m1, Musician m2) {
return m1.dateOfBirth.compareTo(m2.dateOfBirth);
}
});
System.out.println(queen);
// Just do:
queen.sort(Comparator.comparing(Musician::dateOfBirth));
System.out.println(queen);
}
private static List<Musician> getMusicians() {
Musician roger = new Musician("Roger Taylor", LocalDate.of(1949, 7, 26));
Musician john = new Musician("John Deacon", LocalDate.of(1951, 8, 19));
Musician brian = new Musician("Brian May", LocalDate.of(1947, 7, 19));
Musician freddie = new Musician("Freddie Mercury", LocalDate.of(1946, 9, 5));
return Arrays.asList(roger, john, brian, freddie);
}
record Musician(String name, LocalDate dateOfBirth) {
}
}
package com.thegreatapi.ahundreddaysofjava.day046;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Day046 {
public static void main(String[] args) {
List<Musician> queen = getMusicians();
List<Integer> years;
// Instead of doing:
years = new ArrayList<>();
for (Musician musician : queen) {
years.add(musician.dateOfBirth.getYear());
}
System.out.println(years);
// Just do:
years = queen.stream()
.map(musician -> musician.dateOfBirth.getYear())
.collect(Collectors.toList());
System.out.println(years);
}
private static List<Musician> getMusicians() {
Musician roger = new Musician("Roger Taylor", LocalDate.of(1949, 7, 26));
Musician john = new Musician("John Deacon", LocalDate.of(1951, 8, 19));
Musician brian = new Musician("Brian May", LocalDate.of(1947, 7, 19));
Musician freddie = new Musician("Freddie Mercury", LocalDate.of(1946, 9, 5));
return Arrays.asList(roger, john, brian, freddie);
}
record Musician(String name, LocalDate dateOfBirth) {
}
}
package com.thegreatapi.ahundreddaysofjava.day047;
public class Day047 {
@FunctionalInterface
interface Converter {
// Because of the @FunctionalInterface annotation, only one method is allowed in this interface
String convert(Integer number);
}
public static void main(String[] args) {
for (var i = 1; i <= 4; i++) {
System.out.println(i + " in english: " + englishConverter().convert(i));
System.out.println(i + " in portuguese: " + portugueseConverter().convert(i));
System.out.println(i + " in german: " + germanConverter().convert(i));
}
}
private static Converter germanConverter() {
return number -> {
switch (number) {
case 1:
return "eins";
case 2:
return "zwei";
case 3:
return "drei";
case 4:
return "vier";
default:
throw new UnsupportedOperationException();
}
};
}
private static Converter portugueseConverter() {
return number -> {
switch (number) {
case 1:
return "um";
case 2:
return "dois";
case 3:
return "trĂŞs";
case 4:
return "quatro";
default:
throw new UnsupportedOperationException();
}
};
}
private static Converter englishConverter() {
return number -> {
switch (number) {
case 1:
return "one";
case 2:
return "two";
case 3:
return "three";
case 4:
return "four";
default:
throw new UnsupportedOperationException();
}
};
}
}
package com.thegreatapi.ahundreddaysofjava.day048;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.function.UnaryOperator;
public class Day048 {
public static void main(String[] args) {
System.out.println(lastAlbumWith("Slash").apply(getGunsNRosesAlbums()).title());
System.out.println(lastAlbumWith("Slash", "Izzy Stradlin").apply(getGunsNRosesAlbums()).title());
System.out.println(firstAlbumWith("Matt Sorum").apply(getGunsNRosesAlbums()).title());
/*
Output:
The Spaghetti Incident
Use Your Illusion II
Use Your Illusion I
*/
}
private static Function<List<Album>, Album> firstAlbumWith(String... bandMembers) {
return albumsWith(bandMembers).andThen(sortByYear())
.andThen(firstAlbum());
}
private static Function<List<Album>, Album> lastAlbumWith(String... bandMembers) {
return albumsWith(bandMembers).andThen(sortByYear())
.andThen(lastAlbum());
}
private static Function<List<Album>, Album> lastAlbum() {
return albums -> albums.get(albums.size() - 1);
}
private static Function<List<Album>, Album> firstAlbum() {
return albums -> albums.get(0);
}
private static UnaryOperator<List<Album>> sortByYear() {
return albums -> albums.stream()
.sorted(Comparator.comparing(Album::year))
.toList();
}
private static Function<List<Album>, List<Album>> albumsWith(String... bandMembers) {
if (bandMembers.length < 1) {
throw new IllegalArgumentException("");
} else {
Function<List<Album>, List<Album>> resultFunction = albums -> albums;
for (String bandMember : bandMembers) {
resultFunction = resultFunction.andThen(albumsWith(bandMember));
}
return resultFunction;
}
}
private static UnaryOperator<List<Album>> albumsWith(String bandMember) {
return albums -> albums.stream()
.filter(album -> album.lineup().contains(bandMember))
.toList();
}
private static List<Album> getGunsNRosesAlbums() {
List<String> lineup87to90 = List.of("Axl Rose", "Slash", "Izzy Stradlin", "Duff McKagan", "Steven Adler");
List<String> lineup91 = List.of("Axl Rose", "Slash", "Izzy Stradlin", "Duff McKagan", "Matt Sorum", "Dizzy Reed");
List<String> lineup91to93 = List.of("Axl Rose", "Slash", "Gilby Clarke", "Duff McKagan", "Matt Sorum", "Dizzy Reed");
List<String> lineup2008 = List.of("Axl Rose", "Bumblefoot", "Richard Fortus", "Tommy Stinson", "Frank Ferrer", "Chris Pitman", "Dizzy Reed");
return List.of(
new Album("Appetite for Destruction", lineup87to90, 1987),
new Album("G N' R Lies", lineup87to90, 1988),
new Album("Use Your Illusion I", lineup91, 1991),
new Album("Use Your Illusion II", lineup91, 1991),
new Album("The Spaghetti Incident", lineup91to93, 1993),
new Album("Chinese Democracy", lineup2008, 2008)
);
}
private record Album(String title, List<String> lineup, int year) {
}
}
package com.thegreatapi.ahundreddaysofjava.day049;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Day049 {
public static void main(String[] args) {
Map<Integer, String> portugueseNumbers = translateToPortuguese(englishNumbers());
System.out.println(portugueseNumbers);
}
private static Map<Integer, String> translateToPortuguese(Map<Integer, String> numbers) {
/*
Instead of doing:
Function<Integer, Integer> keyMapper = number -> number;
*/
// Just do:
Function<Integer, Integer> keyMapper = Function.identity();
Function<Integer, String> valueMapper = number -> switch (number) {
case 1 -> "um";
case 2 -> "dois";
case 3 -> "trĂŞs";
case 4 -> "quatro";
default -> throw new UnsupportedOperationException("Cannot translate %d".formatted(number));
};
return numbers.keySet()
.stream()
.collect(Collectors.toMap(keyMapper, valueMapper));
}
private static Map<Integer, String> englishNumbers() {
return Map.of(
1, "one",
2, "two",
3, "three",
4, "four"
);
}
}
package com.thegreatapi.ahundreddaysofjava.day050;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public class Day050 {
public static void main(String[] args) {
System.out.println(createPool(10));
System.out.println(enhancedCreatePool(10));
}
// Instead of:
private static List<PooledObject> createPool(int poolSize) {
List<PooledObject> pool = new ArrayList<>(poolSize);
for (var i = 0; i < poolSize; i++) {
pool.add(new PooledObject(String.valueOf(i)));
}
return pool;
}
// Just do:
private static List<PooledObject> enhancedCreatePool(int poolSize) {
return IntStream.range(0, poolSize)
.mapToObj(i -> new PooledObject(String.valueOf(i)))
.toList();
}
private record PooledObject(String id) {
}
}
package com.thegreatapi.ahundreddaysofjava.day051;
import java.util.function.UnaryOperator;
public class Day051 {
public static void main(String[] args) {
// Instead of doing:
// Function<Integer, Integer> multiplyBy2 = i -> i * 2;
// Just do:
UnaryOperator<Integer> multiplyBy2 = i -> i * 2;
System.out.println(multiplyBy2.apply(3));
}
}
package com.thegreatapi.ahundreddaysofjava.day052;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class Day052 {
public static void main(String[] args) {
System.out.println(readFile());
}
public static String readFile() {
try {
return Files.readString(Path.of("/test.txt"));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
package com.thegreatapi.ahundreddaysofjava.day053;
import java.util.logging.Logger;
public class Day053 {
private static final Logger LOGGER = Logger.getLogger(Day053.class.getName());
public static void main(String[] args) {
// Instead of always running the expensive method
// LOGGER.info(veryExpensiveStringCreation());
// Pass the method reference so that it is called only when and if necessary
LOGGER.info(Day053::veryExpensiveStringCreation);
}
private static String veryExpensiveStringCreation() {
try {
Thread.sleep(10_000);
} catch (InterruptedException e) {
//TODO: handle properly
}
return "thegreatapi.com";
}
}
package com.thegreatapi.ahundreddaysofjava.day054;
import java.util.HashMap;
import java.util.Map;
public class Day054 {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
// Instead of doing:
// String three = map.get(3);
// if (three == null) {
// three = "three";
// map.put(3, three);
// }
// Just do:
String three = map.computeIfAbsent(3, k -> "three");
System.out.println(three);
System.out.println(map);
}
}
Day 55 - Creating smart and readable assertions with AssertJ
package com.thegreatapi.ahundreddaysofjava.day055;
public record Day055(String fieldA, Integer fieldB) {
}
package com.thegreatapi.ahundreddaysofjava.day055;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
class Day055Test {
@Test
void testEquals() {
Day055 obj1 = new Day055("thegreatapi.com", 42);
Day055 obj2 = new Day055("thegreatapi.com", 42);
// Intead of using JUnit assertions, like this:
assertEquals(obj1.hashCode(), obj2.hashCode());
// Use AssertJ, like this:
assertThat(obj1).hasSameHashCodeAs(obj2);
}
}
package com.thegreatapi.ahundreddaysofjava.day056;
public final class Day056 {
private static final String RESET_COLOR = "\u001B[0m";
public static void main(String[] args) {
var color = Color.valueOf(args[0]);
System.out.println(color.getAnsiColor() + "thegreatapi.com" + RESET_COLOR);
}
@SuppressWarnings("unused")
enum Color {
BLACK("\u001B[30m"),
BLUE("\u001B[34m"),
RED("\u001B[31m"),
YELLOW("\u001B[33m"),
WHITE("\u001B[37m");
private final String ansiColor;
Color(String ansiColor) {
this.ansiColor = ansiColor;
}
public final String getAnsiColor() {
return ansiColor;
}
}
}
Day 57 - Using Picocli to parse command line arguments
package com.thegreatapi.ahundreddaysofjava.day057;
import picocli.CommandLine;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.Callable;
@CommandLine.Command(
mixinStandardHelpOptions = true,
description = "Prints the contents of the specified file in the specified color")
public class Day057 implements Callable<Integer> {
private static final String RESET_COLOR = "\u001B[0m";
@CommandLine.Option(names = {"-c", "--collor"}, description = "BLACK, BLUE, RED, YELLOW or WHITE")
private Color color;
@CommandLine.Parameters(index = "0", description = "The file whose checksum to calculate.")
private Path path;
@Override
public Integer call() throws Exception {
print(Files.readString(path));
return 0;
}
private void print(String text) {
System.out.println(color.getAnsiColor() + text + RESET_COLOR);
}
public static void main(String... args) {
int exitCode = new CommandLine(new Day057()).execute(args);
System.exit(exitCode);
}
@SuppressWarnings("unused")
enum Color {
BLACK("\u001B[30m"),
BLUE("\u001B[34m"),
RED("\u001B[31m"),
YELLOW("\u001B[33m"),
WHITE("\u001B[37m");
private final String ansiColor;
Color(String ansiColor) {
this.ansiColor = ansiColor;
}
public final String getAnsiColor() {
return ansiColor;
}
}
}
package com.thegreatapi.ahundreddaysofjava.day058;
import java.util.List;
public class Day058 {
static class Bad {
/**
* Never write code that depends on {@link Object#toString()} format.
* The format can change in the future and break your code.
* In this particular case, we don't even know the {@link List} implementation that we're receiving,
* and we don't have any guarantee that the return of {@link List#toString()} would be in the expected format.
*/
public String convertToString(List<String> list) {
return list.toString().replace("[", "").replace("]", "");
}
}
static class Good {
public String convertToString(List<String> list) {
return String.join(", ", list);
}
}
}
package com.thegreatapi.ahundreddaysofjava.day059;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Day059 {
public static void main(String[] args) {
/*
A Predicate<T> is the same as Function<T, Boolean>.
It consumes a T and returns a Boolean.
*/
Predicate<Integer> isPair = intValue -> intValue % 2 == 0;
List<Integer> numbers = getNumbers();
numbers.stream()
.filter(isPair)
.forEach(System.out::println);
}
private static List<Integer> getNumbers() {
return IntStream.rangeClosed(1, 100).boxed().collect(Collectors.toList());
}
}
package com.thegreatapi.ahundreddaysofjava.day060;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static java.util.function.Predicate.not;
public class Day060 {
public static void main(String[] args) {
Predicate<Integer> isEven = intValue -> intValue % 2 == 0;
Predicate<Integer> isPositive = intValue -> intValue > 0;
List<Integer> numbers = getNumbers();
// Prints negative odd numbers and positive even numbers.
numbers.stream()
.filter(isEven.and(isPositive).or(not(isEven).and(not(isPositive))))
.forEach(System.out::println);
}
private static List<Integer> getNumbers() {
return IntStream.rangeClosed(-20, 20).boxed().collect(Collectors.toList());
}
}
Day 61 - Using var
: Good practices, advices and warnings from Stuart Marks
package com.thegreatapi.ahundreddaysofjava.day062;
import jakarta.json.bind.Jsonb;
import jakarta.json.bind.JsonbBuilder;
import java.util.List;
public class Day062 {
public static void main(String[] args) throws Exception {
Musician steveHarris = new Musician("Steve Harris", "Bass", "England", "Iron Maiden");
Musician michaelSchenker = new Musician("Michael Schenker", "Guitar", "Germany", "UFO");
Musician daveLombardo = new Musician("Dave Lombardo", "Drums", "Cuba", "Slayer");
List<Musician> musicians = List.of(steveHarris, michaelSchenker, daveLombardo);
try (Jsonb jsonb = JsonbBuilder.create()) {
String json = jsonb.toJson(musicians);
System.out.println(json);
String jsonJohnLord = "{\"bandName\":\"Deep Purple\",\"country\":\"England\",\"instrument\":\"Keyboards\",\"name\":\"John Lord\"}";
Musician johnLord = jsonb.fromJson(jsonJohnLord, Musician.class);
System.out.println(johnLord);
}
}
public static class Musician {
private String name;
private String instrument;
private String country;
private String bandName;
public Musician() {
}
public Musician(String name, String instrument, String country, String bandName) {
this.name = name;
this.instrument = instrument;
this.country = country;
this.bandName = bandName;
}
// Getters and setters...
@Override
public String toString() {
return "Musician{" +
"name='" + name + '\'' +
", instrument='" + instrument + '\'' +
", country='" + country + '\'' +
", bandName='" + bandName + '\'' +
'}';
}
}
}
package com.thegreatapi.ahundreddaysofjava;
import org.eclipse.microprofile.faulttolerance.Fallback;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.time.Instant;
@Path("/hello")
public class Day063 {
@GET
@Fallback(fallbackMethod = "fallbackHello")
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
if (Instant.now().toEpochMilli() % 2 == 0) {
return "Hello from the main method";
} else {
throw new RuntimeException();
}
}
public String fallbackHello() {
return "Hello from the fallback method";
}
}
package com.thegreatapi.ahundreddaysofjava.day064;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import static java.util.stream.Collectors.partitioningBy;
public class Day064 {
public static void main(String[] args) {
Predicate<Band> isEuropeanBand = band -> List.of(Europe.values()).contains(band.country);
Map<Boolean, List<Band>> europeanBandsAndOthers = getBands().stream()
.collect(partitioningBy(isEuropeanBand));
List<Band> europeanBands = europeanBandsAndOthers.get(true);
List<Band> otherBands = europeanBandsAndOthers.get(false);
System.out.println("Bands from Europe: " + europeanBands);
System.out.println("Other bands: " + otherBands);
}
private static List<Band> getBands() {
return List.of(
new Band("Sepultura", America.BRAZIL),
new Band("Gojira", Europe.FRANCE),
new Band("Rush", America.CANADA),
new Band("AC/DC", Oceania.NEW_ZEALAND),
new Band("Iron Maiden", Europe.ENGLAND),
new Band("Scorpions", Europe.GERMANY),
new Band("Kiss", America.USA),
new Band("Mastodon", America.USA)
);
}
static record Band(String name, Country country) {
}
interface Country {
}
enum Europe implements Country {
ENGLAND,
GERMANY,
FRANCE
}
enum America implements Country {
BRAZIL,
ARGENTINA,
USA,
CANADA
}
enum Oceania implements Country {
AUSTRALIA,
NEW_ZEALAND
}
}
package com.thegreatapi.ahundreddaysofjava.day065;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Day065 {
public static void main(String[] args) {
// Instead of doing:
Map<Integer, List<Integer>> map1 = new HashMap<Integer, List<Integer>>();
// Just do:
Map<Integer, List<Integer>> map2 = new HashMap<>();
}
}
package com.thegreatapi.ahundreddaysofjava.day066;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import java.time.LocalDate;
public class Day066 {
// Instead of doing:
@AllArgsConstructor
@ToString
@EqualsAndHashCode
class PersonLombok {
@Getter
private final String name;
@Getter
private final LocalDate dateOfBirth;
@Getter
private final String country;
}
// Just do: (requires JDK 16)
record PersonPureJava(String name, LocalDate dateOfBirth, String country) {
}
}
package com.thegreatapi.ahundreddaysofjava.day067;
import java.util.EnumMap;
import java.util.Map;
public class Day067 {
public static void main(String[] args) {
/*
Use EnumMap when the key of your Map is an enum.
EnumMap is more efficient than HashMap.
*/
Map<Color, String> portugueseColors = new EnumMap<>(Color.class);
portugueseColors.put(Color.RED, "Vermelho");
portugueseColors.put(Color.YELLOW, "Amarelo");
portugueseColors.put(Color.BLUE, "Azul");
}
enum Color {
RED,
YELLOW,
BLUE
}
}
var interestingClasses = List.of(Integer.class, Number.class, String.class);
// Instead of doing:
List<String> interestingClassNames = interestingClasses.stream()
.map(Class::getName)
.toList();
Optional<Class<?>> class1 = Arrays.stream(Thread.currentThread().getStackTrace())
.map(StackTraceElement::getClassName)
.filter(interestingClassNames::contains)
.findFirst()
.map(className -> {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
});
// Just do:
Optional<Class<?>> class2 = StackWalker.getInstance(RETAIN_CLASS_REFERENCE).walk(
stackFrameStream -> stackFrameStream.<Class<?>>map(StackWalker.StackFrame::getDeclaringClass)
.filter(interestingClasses::contains)
.findFirst()
);
package com.thegreatapi.ahundreddaysofjava.day069;
import java.security.SecureRandom;
import java.util.stream.Stream;
public class Day069 {
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
public static void main(String[] args) {
Stream.generate(() -> SECURE_RANDOM.nextInt(99) + 1)
.forEach(System.out::println);
}
}
package com.thegreatapi.ahundreddaysofjava.day070;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.time.LocalDate;
import java.util.stream.Stream;
import static com.thegreatapi.ahundreddaysofjava.day070.Day070.Person;
import static org.assertj.core.api.Assertions.assertThat;
class Day070Test {
private static Stream<Arguments> isYearsHigherThanSource() {
Person peter = new Person("Peter", LocalDate.of(1950, 1, 1));
Person john = new Person("John", LocalDate.of(2015, 1, 1));
Person mary = new Person("Mary", LocalDate.of(2003, 1, 1));
return Stream.of(
Arguments.of(peter, 18, true),
Arguments.of(john, 18, false),
Arguments.of(mary, 18, true)
);
}
@ParameterizedTest
@MethodSource("isYearsHigherThanSource")
void isYearsHigherThan(Person person, int years, boolean expectedResult) {
assertThat(person.isYearsHigherThan(years))
.isEqualTo(expectedResult);
}
}
package com.thegreatapi.ahundreddaysofjava.day071;
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
public class Day071 {
public static void main(String[] args) {
Weld weld = new Weld();
WeldContainer container = weld.initialize();
Application application = container.select(Application.class).getHandler().get();
application.run();
container.shutdown();
}
}
package com.thegreatapi.ahundreddaysofjava.day071;
import com.thegreatapi.ahundreddaysofjava.day071.animal.Calculator;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
class Application {
private final Calculator animal;
@Inject
private Application(Calculator animal) {
this.animal = animal;
}
public void run() {
System.out.println(animal.sum(2, 3));
}
}
package com.thegreatapi.ahundreddaysofjava.day071.animal;
public interface Calculator {
int sum(int a, int b);
}
package com.thegreatapi.ahundreddaysofjava.day071.animal;
class CalculatorImpl implements Calculator {
private CalculatorImpl() {
}
@Override
public int sum(int a, int b) {
return a + b;
}
}
package com.thegreatapi.ahundreddaysofjava.day072;
import com.thegreatapi.ahundreddaysofjava.day072.animal.Animal;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@ApplicationScoped
class Application {
private final Animal dog;
private final Animal cat;
@Inject
private Application(@Named("Dog") Animal dog, @Named("Cat") Animal cat) {
this.dog = dog;
this.cat = cat;
}
public void run() {
System.out.println("The dog says: " + dog.speak());
System.out.println("The cat says: " + cat.speak());
}
}
package com.thegreatapi.ahundreddaysofjava.day072.animal;
import jakarta.inject.Named;
@Named("Dog")
class Dog implements Animal {
private Dog() {
}
@Override
public String speak() {
return "woof";
}
}
package com.thegreatapi.ahundreddaysofjava.day072.animal;
import jakarta.inject.Named;
@Named("Cat")
class Cat implements Animal {
private Cat(){
}
@Override
public String speak() {
return "meow";
}
}
package com.thegreatapi.ahundreddaysofjava.day073;
import com.thegreatapi.ahundreddaysofjava.day073.paymentprocessor.Asynchronous;
import com.thegreatapi.ahundreddaysofjava.day073.paymentprocessor.Payment;
import com.thegreatapi.ahundreddaysofjava.day073.paymentprocessor.PaymentProcessor;
import jakarta.inject.Inject;
import java.math.BigDecimal;
class Application {
private final PaymentProcessor paymentProcessor;
@Inject
private Application(@Asynchronous PaymentProcessor paymentProcessor) {
this.paymentProcessor = paymentProcessor;
}
public void run() {
paymentProcessor.process(new Payment("1234", BigDecimal.TEN));
}
}
package com.thegreatapi.ahundreddaysofjava.day073.paymentprocessor;
public interface PaymentProcessor {
void process(Payment payment);
}
package com.thegreatapi.ahundreddaysofjava.day073.paymentprocessor;
@Synchronous
class SynchronousPaymentProcessor implements PaymentProcessor {
@Override
public void process(Payment payment) {
System.out.println("Processing payment " + payment + " synchronously");
}
}
package com.thegreatapi.ahundreddaysofjava.day073.paymentprocessor;
@Asynchronous
class AsynchronousPaymentProcessor implements PaymentProcessor {
@Override
public void process(Payment payment) {
System.out.println("Processing payment " + payment + " asynchronously");
}
}
package com.thegreatapi.ahundreddaysofjava.day073.paymentprocessor;
import jakarta.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface Asynchronous {
}
package com.thegreatapi.ahundreddaysofjava.day073.paymentprocessor;
import jakarta.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface Synchronous {
}
package com.thegreatapi.ahundreddaysofjava.day074;
import java.util.function.Consumer;
public class Day074 {
public static void main(String[] args) {
Person daveMustaine = new Person("Dave Mustaine", "Megadeth");
// A consumer is a Function that uses an argument and returns nothing. Like Function<Person, Void>.
Consumer<Person> personConsumer = person -> System.out.printf(
"%s from %s sings: %s%n", daveMustaine.name, daveMustaine.bandName, "\"Holy waaaars\""
);
daveMustaine.sing(personConsumer);
}
private static record Person(String name, String bandName) {
void sing(Consumer<Person> consumer) {
consumer.accept(this);
}
}
}
package com.thegreatapi.ahundreddaysofjava.day075;
import jakarta.inject.Inject;
class Application {
private final PaymentProcessor paymentProcessor;
@Inject
private Application(PaymentProcessor paymentProcessor) {
this.paymentProcessor = paymentProcessor;
}
public void run() {
paymentProcessor.process(new Payment());
}
}
package com.thegreatapi.ahundreddaysofjava.day075;
import jakarta.enterprise.inject.Produces;
final class PaymentProcessorFactory {
private PaymentProcessorFactory() {
}
@Produces
static PaymentProcessor createPaymentProcessor() {
return new PaymentProcessorImpl(new DependencyA(), new DependencyB());
}
}
package com.thegreatapi.ahundreddaysofjava.day076;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.time.LocalDate;
import java.util.List;
@Path("/person")
public class Day076 {
// To start the server, run:
// mvn compile quarkus:dev
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Person> getPeople() {
return List.of(
new Person("1", "Ozzy Osbourne", LocalDate.of(1948, 12, 3)),
new Person("2", "Tony Iommi", LocalDate.of(1948, 2, 19)),
new Person("3", "Geezer Butler", LocalDate.of(1948, 7, 19)),
new Person("4", "Bill Ward", LocalDate.of(1948, 5, 5))
);
}
public static class Person {
private final String id;
private final String name;
private final LocalDate dateOfBirth;
public 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;
}
}
}
package com.thegreatapi.ahundreddaysofjava.day078;
import java.util.List;
import java.util.function.Function;
public class Day078 {
public static void main(String[] args) {
int input1 = 42;
String output1 = map(input1, obj -> "The value is " + obj);
System.out.println(output1);
String[] input2 = {"a", "b", "c"};
List<String> output2 = map(input2, List::of);
System.out.println(output2);
}
private static <T, R> R map(T input, Function<T, R> function) {
return function.apply(input);
}
}
package com.thegreatapi.ahundreddaysofjava.day079;
import com.thegreatapi.ahundreddaysofjava.day079.myservice.MyService;
import com.thegreatapi.ahundreddaysofjava.day079.myservice.MyServiceFactory;
public class Day079 {
public static void main(String[] args) {
// This class has access to MyService and MyServiceFactory, but not MyServiceImpl
MyService myService = MyServiceFactory.createMyService();
myService.run();
}
}
package com.thegreatapi.ahundreddaysofjava.day079.myservice;
public interface MyService {
void run();
}
package com.thegreatapi.ahundreddaysofjava.day079.myservice;
class MyServiceImpl implements MyService {
@Override
public void run() {
System.out.println("Running my service...");
}
}
package com.thegreatapi.ahundreddaysofjava.day079.myservice;
public final class MyServiceFactory {
private MyServiceFactory() {
}
public static MyService createMyService() {
return new MyServiceImpl();
}
}
package com.thegreatapi.ahundreddaysofjava.day080;
public class Day080 {
private sealed interface Animal permits Dog, Cat {
void speak();
}
private static non-sealed class Dog implements Animal {
@Override
public void speak() {
System.out.println("Woof");
}
}
private static final class Cat implements Animal {
@Override
public void speak() {
System.out.println("Meow");
}
}
private static class Bird implements Animal { // Error: Bird is not allowed in the sealed hierarchy
@Override
public void speak() {
System.out.println("Pew");
}
}
}
package com.thegreatapi.ahundreddaysofjava.day081;
import java.util.Collections;
import java.util.List;
public class Day081 {
public static void main(String[] args) {
List<Integer> list = List.of(6, 3, 1, 2, 4, 2, 5, 8, 4, 5, 3);
int frequency = Collections.frequency(list, 4);
System.out.println(frequency);
}
}
package com.thegreatapi.ahundreddaysofjava.day082;
public class Day082 {
public static void main(String[] args) {
int a = 2;
int b = Integer.MAX_VALUE;
long uncastedLong = a * b;
System.out.println(uncastedLong); // Prints: -2
long castedLong = (long) a * b;
System.out.println(castedLong); // Prints: 4294967294
}
}
package com.thegreatapi.ahundreddaysofjava.day083;
import org.eclipse.microprofile.faulttolerance.Timeout;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.time.temporal.ChronoUnit;
@Path("/hello")
public class Day083 {
@GET
@Timeout(value = 1, unit = ChronoUnit.SECONDS)
@Produces(MediaType.TEXT_PLAIN)
public String hello() throws InterruptedException {
Thread.sleep(1500);
return "";
}
}
package com.thegreatapi.ahundreddaysofjava.day084;
import org.eclipse.microprofile.faulttolerance.Retry;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.time.temporal.ChronoUnit;
@Path("/hello")
public class Day084 {
private static int numberOfAttempts = 0;
@GET
@Retry(maxRetries = 3, delay = 2, delayUnit = ChronoUnit.SECONDS)
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
numberOfAttempts++;
if (numberOfAttempts < 3) {
throw new RuntimeException("Emulates an error");
} else {
return "Hello after " + numberOfAttempts + " attempts";
}
}
}
package com.thegreatapi.ahundreddaysofjava.day085;
import org.eclipse.microprofile.faulttolerance.Retry;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.security.SecureRandom;
import java.time.temporal.ChronoUnit;
@Path("/hello")
public class Day085 {
private static final SecureRandom RANDOM = new SecureRandom();
private static int numberOfAttempts;
@GET
@Retry(retryOn = MyCustomException.class, maxRetries = 3, delay = 2, delayUnit = ChronoUnit.SECONDS)
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
numberOfAttempts++;
if (numberOfAttempts < 3) {
if (RANDOM.nextBoolean()) {
// Will throw MyCustomException and will retry
throw new MyCustomException();
} else {
// Will throw RuntimeException and won't retry
throw new RuntimeException();
}
} else {
return "Hello after " + numberOfAttempts + " attempts";
}
}
static class MyCustomException extends RuntimeException {
private static final long serialVersionUID = 6631584573985699096L;
}
}
package com.thegreatapi.ahundreddaysofjava.day086;
public class Day086 {
public static void main(String[] args) {
var toUpperStrategy = new ToUpperStrategy(IdentityStrategy.getInstance());
var addPrefixStrategy = new AddPrefixStrategy(toUpperStrategy);
var trimStrategy = new TrimStrategy(addPrefixStrategy);
String result = trimStrategy.apply(" thegreatapi.com ");
System.out.println(result);
}
@FunctionalInterface
interface Strategy {
String apply(String s);
}
abstract static class AbstractStrategy implements Strategy {
private final Strategy delegate;
protected AbstractStrategy(Strategy delegate) {
this.delegate = delegate;
}
@Override
public String apply(String s) {
return delegate.apply(doApply(s));
}
protected abstract String doApply(String s);
}
static class ToUpperStrategy extends AbstractStrategy {
ToUpperStrategy(Strategy delegate) {
super(delegate);
}
@Override
protected String doApply(String s) {
return s.toUpperCase();
}
}
static class TrimStrategy extends AbstractStrategy {
protected TrimStrategy(Strategy delegate) {
super(delegate);
}
@Override
protected String doApply(String s) {
return s.trim();
}
}
static class AddPrefixStrategy extends AbstractStrategy {
protected AddPrefixStrategy(Strategy delegate) {
super(delegate);
}
@Override
protected String doApply(String s) {
return "~> " + s;
}
}
static class IdentityStrategy implements Strategy {
private static final IdentityStrategy INSTANCE = new IdentityStrategy();
private IdentityStrategy() {
}
static IdentityStrategy getInstance() {
return INSTANCE;
}
@Override
public String apply(String s) {
return s;
}
}
}
package com.thegreatapi.ahundreddaysofjava.day087;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class Day087 {
public static void main(String[] args) {
var myAnnotatedObject = new AnnotatedClass();
var myNonAnnotatedObject = new NonAnnotatedClass();
System.out.println(isAnnotated(myAnnotatedObject)); // Prints: true
System.out.println(isAnnotated(myNonAnnotatedObject)); // Prints: false
}
private static boolean isAnnotated(Object object) {
return object.getClass().isAnnotationPresent(MyAnnotation.class);
}
@MyAnnotation
static class AnnotatedClass {
}
static class NonAnnotatedClass {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface MyAnnotation {
}
}
package com.thegreatapi.ahundreddaysofjava.day088;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class Day088 {
public static void main(String[] args) throws NoSuchFieldException {
var myObject = new MyClass(2021, 8);
System.out.println(isAnnotated(myObject, "year")); // Prints: true
System.out.println(isAnnotated(myObject, "month")); // Prints: true
}
private static boolean isAnnotated(Object object, String fieldName) throws NoSuchFieldException {
return object.getClass().getDeclaredField(fieldName).isAnnotationPresent(MyAnnotation.class);
}
static class MyClass {
@MyAnnotation
private final int year;
private final int month;
MyClass(int year, int month) {
this.year = year;
this.month = month;
}
public int getYear() {
return year;
}
public int getMonth() {
return month;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface MyAnnotation {
}
}