8 reasons why Java is the greatest language ever made 21/09/2020

Most developers who have never worked with Java often have a biased view of the language.

They talk about Java as if the language hadn't changed since version 5. Java is slow, the generics were poorly implemented, the syntax is ten years late, etc.

However, since the release of java 8, the language has evolved over the years, allowing developers to use the most modern programming techniques.

At present, given the evolution of the java language, I personally find that all alternatives (Scala, Kotlin, Clojure, etc.) no longer need to be and do not bring much, except syntax sugar.

So I list here 8 features of the Java language that I use regularly in my projects.

1. Grouping By

Imagine a list of Vehicle objects, which you want to group by color:

// Vehicle.java
public class Vehicle {
public enum Color {RED,BLUE,ORANGE,BLACK}
private String model;
private Color color;
// constructor & getter
}
List<Vehicle> vehicles =
List.of(
new Vehicle("Renault", Vehicle.Color.ORANGE),
new Vehicle("Mercedes", Vehicle.Color.BLACK),
new Vehicle("Peugeot", Vehicle.Color.RED),
new Vehicle("BMW", Vehicle.Color.BLUE),
new Vehicle("Fiat", Vehicle.Color.RED),
new Vehicle("Ford", Vehicle.Color.BLACK)
);

We use streams to group them:

Map<Vehicle.Color, List<Vehicle>> grouped = 
vehicles.stream().collect(Collectors.groupingBy(Vehicle::getColor));

Output:

RED=[Vehicle{model='Peugeot', color=RED}, 
Vehicle{model='Fiat', color=RED}]

ORANGE=[Vehicle{model='Renault', color=ORANGE}] 

BLUE=[Vehicle{model='BMW', color=BLUE}]

BLACK=[Vehicle{model='Mercedes', color=BLACK}, 
Vehicle{model='Ford', color=BLACK}]

2. Optional

Optionals are used to avoid "NullPointerException" errors at Runtime. We can use Optionals as streams:

public boolean isColorOfVehicleBlack(Vehicle vehicleCouldBeNull) {
return Optional.ofNullable(vehicleCouldBeNull)
           .map(Vehicle::getColor) // color could also be null...
           .stream() 
           .anyMatch(Vehicle.Color.BLACK::equals);
}

3. String block

A String block allows you to write text on multiple lines without having to use concatenation.

This syntax was introduced in draft in Java 13 and has been standardized in java 15.

Here's how we declare a string block:

String json = """
   {
       model: "Mercedes",
       color: "RED"
   }
""";

4. Asynchronous

To run asynchronous code, we use the CompletableFuture class. Here are some examples of use:

import java.math.BigDecimal;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

import static java.lang.System.out;
import static java.math.RoundingMode.CEILING;
import static java.util.concurrent.CompletableFuture.*;

class Scratch {
public static void main(String[] args) {
out.println("Start....");
runAsync(() -> out.println("Run asynchronously!"));
out.println("End....");

out.println("Start Delayed....");
Executor delay = delayedExecutor(2000, TimeUnit.MILLISECONDS);

runAsync(() -> out.println("Delayed 2 seconds!"), delay).join();
out.println("End Delayed....");

supplyAsync(() -> new BigDecimal("99.88922"))
.thenCombine(completedStage(new BigDecimal(1)), BigDecimal::add)
.whenComplete(
   (bigDecimal, throwable) -> out.println("Result : " + bigDecimal.setScale(2, CEILING)))
.join();
}
}

5. Http Client

Java 11 introduced an advanced, very convenient and easy-to-use Http client:

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

import static java.lang.System.out;

class Scratch {
public static void main(String[] args) {
String httpResponse = HttpClient.newHttpClient().sendAsync(
     HttpRequest.newBuilder()
             .GET()
             .uri(URI.create("http://openlibrary.org/authors/OL1A.json"))
             .build()
     , HttpResponse.BodyHandlers.ofString())
     .handleAsync((stringHttpResponse, throwable) -> stringHttpResponse.body())
     .join();

out.println(httpResponse);
}
}

6. Switch / Yield

It is no longer necessary to create a separate method to assign a value to a variable according to the result of a switch:

import java.util.concurrent.ThreadLocalRandom;

class Scratch {
enum Color {RED, ORANGE}
public static void main(String[] args) {
ThreadLocalRandom random = ThreadLocalRandom.current();
var result = random.nextInt(0,10);
String message = switch (result){
 case 0,1,2,3,4 ->   "Good job!";
 case 5 -> "Be careful next year...";
 case 6,7,8,9 ->  "that's bad";
 default ->  "Meh";
};
System.out.println(message);
var randomColor = random.nextBoolean() ? Color.RED : Color.ORANGE;
String favoriteColor = switch (randomColor){
case RED: yield "Your favorite color is red";
case ORANGE: yield "Your favorite color is orange";
} ;
System.out.println(favoriteColor);
}

}

7. Time api

The time API is very useful for manipulating dates. Useless in most cases to use Calendar or SimpleDateFormat ...

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

class Scratch {
public static void main(String[] args) {
String dateFormatted =
LocalDateTime.now()
   .plusDays(30)
   .truncatedTo(ChronoUnit.MINUTES)
   .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
System.out.printf("Date in 30 days %s", dateFormatted);
}

}

8. Lombok

This library quickly became essential and allows us to avoid writing boiler plate code (getter / setter, builder, toString, hashCode / equals, ...)

public static void main(String[] args) {
Vehicle mercedes = Vehicle.builder().model("Mercedes").price(new BigDecimal("50000")).build();
System.out.println(mercedes.getModel());
Vehicle renault = mercedes.toBuilder().model("Renault").build();
System.out.printf("%s: $%s", renault.getModel(), renault.getPrice());
}

@Value
@Builder(toBuilder = true)
static class Vehicle {
String model;
BigDecimal price;
}

Conclusion

<troll>
ng build --prod
</troll>