JavaRush /Java Blog /Random EN /Coffee break #37. A new future for Java. JVM, Kotlin and ...

Coffee break #37. A new future for Java. JVM, Kotlin and Java prospects after 2020

Published in the Random EN group
Source: Medium Java is mainly criticized for two things: verbosity and the amount of boilerplate code that is generated in many cases without obvious need. Although I've always liked Java, I can't say that these statements are wrong. It's really true: excessive detail in Java can sometimes be very annoying. However, we must admit that we do not live in an ideal world, and in most cases we have to choose the lesser of two evils. Coffee break #37.  A new future for Java.  JVM, Kotlin and Java prospects after 2020 - 1Since its inception, Java has not been perfect: we all know this, but the real question is why nothing was done before to solve these problems. I think the only reason the changes took so long is because the Java language lacked competition and things were just the way they were. Java dominated the market, probably due to the lack of serious competitors and the great efforts made first by Sun and then by Oracle. The high level of type safety that Java provides and the good structuring of the language have made it very popular for large projects. In addition, it is a multi-platform language that runs on its own virtual machine. Combined with automatic performance optimization via the JIT compiler, all this minimizes the impact of poorly written code. All in all, it's a pretty compelling set of reasons to use Java. But what happened next? What has happened is that new languages ​​have come onto the market that can run in the same JVM as Java. Languages ​​that eliminated some of the biggest inconveniences in Java and, in some cases, offered developers a more pleasant environment with a lower barrier to entry. Before we continue, let's take stock and take a brief look at the history of JVM languages.

History of JVM languages

First, I'd like to make one thing clear: I didn't mention some of the existing JVM languages ​​because they never had enough support to be considered candidates for widespread use in our industry. Let us now begin our brief overview of the history of JVM languages. First up we'll have Java, the oldest and most popular language in the JVM world. Java was officially released in January 1996, so the language has been around for 24 years. Not bad, right? Java was originally a purely imperative language that followed an object-oriented programming style; it was also a strongly typed language. Java's syntax is somewhat similar to C++ and C languages, but it is considered an improved version because writing code in Java is much easier than in C or C++. On the other hand, we have the biggest argument among his detractors - verbosity. The second JVM language was Groovy. It has been around since 2003, although its first standardized version, 1.0, only appeared in January 2007. The advantage of Groovy is that it can be used as a scripting language. Groovy is a dynamically typed language, so type checking is done at runtime. This is one of the reasons why some developers don't like Groovy. You write your code in Groovy and it looks correct at compile time, but then at runtime you realize something is wrong. Then another popular language appeared: we talk about Scala. It was released in 2004. He brought a new model of work to the JVM world: functional programming and a declarative approach. Basically, Scala was the first language to introduce the concept of immutability, which was then used to enhance Java. On the other hand, detractors do not like Scala because of its complex grammar and rather low readability. The next language to emerge from the JVM world was Clojure, a purely functional language. It has become quite popular recently, although it appeared back in 2007. Clojure is a LISP-based language that is characterized by its simplicity and use of simple functions. Among its disadvantages are that it is dynamically typed (like Groovy) and the learning curve is much steeper since its syntax is completely different from other JVM languages. And finally, we have Kotlin. Kotlin first appeared in February 2016, and since then its popularity has not stopped growing. It is developed by JetBrains with the main goal: to fix the most famous Java problems. By design, Kotlin retained all the advantages of Java, but at the same time solved many problems. These are the most important JVM languages. As I said, we missed some other languages ​​that are not so popular: Jython, JRuby, Ceylon, Fantom, etc. If you wish, you can find out the entire list of existing JVM languageson Wikipedia. You've probably realized that Java didn't have much competition in the first eight or ten years after its creation, but things have changed since then. So, is competition good or bad?

Benefits of Increasing Competition

Java hasn't changed much in its early years. Probably because it wasn't necessary. This language has been widely used and has always been very popular, despite the fact that it is far from perfect. But then competitors appeared, more modern languages ​​that offered new features and solved some of the problems that had plagued Java developers for a long time. For example, let's look at the Scala language. Scala's popularity has been growing since 2009. Developers welcomed this new functional style, which gave them greater flexibility as well as the ability to write parallel code safely and easily. How has Oracle responded to this new trend? In 2014, Java Lambdas and Streams appeared. I think we can all agree that this is when Java took its biggest step towards defeating Scala. Now any programmer knows that Scala is no longer trendy. Coffee break #37.  A new future for Java.  JVM, Kotlin and Java prospects after 2020 - 2Another benefit of having more competitors in the JVM world is the constant improvements being made to the JIT compiler and JVM. Now a lot more people are interested in optimizing the JVM and improving performance. So competition is good for everyone! The most recent alternative to Java is the Kotlin language. Its appearance was very important for the development of Java, since the new language, in a sense, showed Oracle the way forward. The Kotlin example showed that it is possible to preserve the advantages of Java, but create a more compact language in which it is faster to write code. If you look at the Google Trends graph, you can see that from 2016 to 2018, the popularity of Kotlin grew rapidly. But over the past two years the excitement has dropped. Coffee break #37.  A new future for Java.  JVM, Kotlin and Java prospects after 2020 - 3Oracle has taken a close look at the industry's response to Kotlin. If you look at the JDK 15 release notes , you'll see that some of the new Java features are copies of what came in Kotlin. These are new Java entries , new text blocks (multiline strings with triple quotes) and a new operator switch, which is essentially a copy of the operator whenin Kotlin. Everything we talked about is what I call “Kotlinization of Java.” By becoming a stronger competitor, Kotlin showed Java the path to follow.

"Kotlinization" of Java

Some of the upcoming Java features will be significant improvements in terms of readability and will address one of the biggest weaknesses of the Java language - its verbosity. One could argue that many of the announced Java features are suspiciously similar to some Kotlin features. But please note that most of them are pre-release versions . This means that if you install JDK 14 or JDK 15 (when it's released), you won't be able to use them by default. Java feature previews are new features that are introduced in a release but are disabled by default. They are included in the new version only to gather feedback from the developer community, so they may still be subject to change. This is why it is not recommended to use them in production code. To enable them at compile time you will need to do the following:
javac --enable-preview --release 14
If you want to enable them at runtime, you will need to run the following:
java --enable-preview YourClass
Of course, you can also enable them in your IDE, but be careful not to enable preview by default in all your new projects! Let's take a look at the changes that will have a greater impact on our coding in future versions of Java.

Java Posts

Java Records is a feature that many of us have been clamoring for for a long time. I'm guessing you've found yourself in a situation where you needed to implement toString , hashCode , equals , as well as getters for every existing field. Kotlin has data classes to solve this problem , and Java intends to do the same by releasing record classes that Scala already has in the form of case classes . The main purpose of these classes is to store immutable data in an object. Let's take an example to see how much better Java can become. This is how much code we would have to write to create and compare our class Employee:
package com.theboreddev.java14;

import java.util.Objects;

public class Employee {
    private final String firstName;
    private final String surname;
    private final int age;
    private final Address address;
    private final double salary;

    public Employee(String firstName, String surname, int age, Address address, double salary) {
        this.firstName = firstName;
        this.surname = surname;
        this.age = age;
        this.address = address;
        this.salary = salary;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getSurname() {
        return surname;
    }

    public int getAge() {
        return age;
    }

    public Address getAddress() {
        return address;
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age == employee.age &&
                Double.compare(employee.salary, salary) == 0 &&
                Objects.equals(firstName, employee.firstName) &&
                Objects.equals(surname, employee.surname) &&
                Objects.equals(address, employee.address);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstName, surname, age, address, salary);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "firstName='" + firstName + '\'' +
                ", surname='" + surname + '\'' +
                ", age=" + age +
                ", address=" + address +
                ", salary=" + salary +
                '}';
    }
}
And also the object Addressit contains:
import java.util.Objects;

public class Address {
    private final String firstLine;
    private final String secondLine;
    private final String postCode;

    public Address(String firstLine, String secondLine, String postCode) {
        this.firstLine = firstLine;
        this.secondLine = secondLine;
        this.postCode = postCode;
    }

    public String getFirstLine() {
        return firstLine;
    }

    public String getSecondLine() {
        return secondLine;
    }

    public String getPostCode() {
        return postCode;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Address address = (Address) o;
        return Objects.equals(firstLine, address.firstLine) &&
                Objects.equals(secondLine, address.secondLine) &&
                Objects.equals(postCode, address.postCode);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstLine, secondLine, postCode);
    }

    @Override
    public String toString() {
        return "Address{" +
                "firstLine='" + firstLine + '\'' +
                ", secondLine='" + secondLine + '\'' +
                ", postCode='" + postCode + '\'' +
                '}';
    }
}
There's probably too much code for something so simple, right? Let's now see how this will look with the new Java entries:
public record EmployeeRecord(String firstName, String surname, int age, AddressRecord address, double salary) {
}
And let's not forget the Address class:
public record AddressRecord(String firstLine, String secondLine, String postCode) {
}
This is the same thing we wrote earlier with so much code. Agree: this is amazing. And the amount of code we're going to save, and the ease of writing! Let's now see what the differences are with the new operator switch.

Improved Operatorswitch

The new operator switchin Java will solve some of the old problems, including some bugs and code duplication. With the new operator switchthis problem will be solved. To explain this with an example, we are going to create an enum DayOfTheWeekin Java:
public enum DayOfTheWeek {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}
After that, ours switchwill tell us which position in the week corresponds to that day. Let's first see how we can do this currently using Java 11.
final DayOfTheWeek dayOfTheWeek = DayOfTheWeek.THURSDAY;

        int position = 0;

        switch (dayOfTheWeek) {
            case MONDAY:
                position = 1;
                break;
            case TUESDAY:
                position = 2;
                break;
            case WEDNESDAY:
                position = 3;
                break;
            case THURSDAY:
                position = 4;
                break;
            case FRIDAY:
                position = 5;
                break;
            case SATURDAY:
                position = 6;
                break;
            case SUNDAY:
                position = 7;
                break;
        }

        System.out.println("Day " + dayOfTheWeek + " is in position " + position + " of the week");
With the current statement, switchwe will need to use a variable, and if we miss one of the days of the week, our code will compile just fine. This is one of the problems with operators switch: they are too error prone. So how does Java 14 improve things? Let's get a look:
final DayOfTheWeek dayOfTheWeek = DayOfTheWeek.THURSDAY;

        int position = switch (dayOfTheWeek) {
            case MONDAY -> 1;
            case TUESDAY -> 2;
            case WEDNESDAY -> 3;
            case THURSDAY -> 4;
            case FRIDAY -> 5;
            case SATURDAY -> 6;
            case SUNDAY -> 7;
        };

        System.out.println("Day " + dayOfTheWeek + " is in position " + position + " of the week");
As you can see, the new operators switchcan be used as an expression, not just as a statement. The result is more concise and expressive. This would be enough to convince many of us to use them, but one of the major improvements is that now the statements switchwill not compile unless we cover all cases in our switch. It will show us this error, for example:
Error:(9, 24) java: the switch expression does not cover all possible input values
From now on, it will be impossible to skip case in our operators switch. This is very similar to operators whenin Kotlin, which you can read about in the documentation . Let's also take a look at the new text blocks.

Text blocks

Have you ever complained about how difficult it is to assign a JSON blob to a variable in Java? Java has multiline sequences that you can describe by enclosing them in triple quotes. Once this feature is officially released, it will become much easier to describe long sequences over multiple lines. Let's look at the differences between the two modes. If we want to use formatted JSON in a variable, it turns out bad:
final String text = "{\"widget\": {\n" +
                "    \"debug\": \"on\",\n" +
                "    \"window\": {\n" +
                "        \"title\": \"Sample Konfabulator Widget\",\n" +
                "        \"name\": \"main_window\",\n" +
                "        \"width\": 500,\n" +
                "        \"height\": 500\n" +
                "    },\n" +
                "    \"image\": { \n" +
                "        \"src\": \"Images/Sun.png\",\n" +
                "        \"name\": \"sun1\",\n" +
                "        \"hOffset\": 250,\n" +
                "        \"vOffset\": 250,\n" +
                "        \"alignment\": \"center\"\n" +
                "    },\n" +
                "    \"text\": {\n" +
                "        \"data\": \"Click Here\",\n" +
                "        \"size\": 36,\n" +
                "        \"style\": \"bold\",\n" +
                "        \"name\": \"text1\",\n" +
                "        \"hOffset\": 250,\n" +
                "        \"vOffset\": 100,\n" +
                "        \"alignment\": \"center\",\n" +
                "        \"onMouseUp\": \"sun1.opacity = (sun1.opacity / 100) * 90;\"\n" +
                "    }\n" +
                "}} ";
On the other hand, when the new text blocks are released, everything will become much simpler:
final String multiLineText = """
                {"widget": {
                    "debug": "on",
                    "window": {
                        "title": "Sample Konfabulator Widget",
                        "name": "main_window",
                        "width": 500,
                        "height": 500
                    },
                    "image": {\s
                        "src": "Images/Sun.png",
                        "name": "sun1",
                        "hOffset": 250,
                        "vOffset": 250,
                        "alignment": "center"
                    },
                    "text": {
                        "data": "Click Here",
                        "size": 36,
                        "style": "bold",
                        "name": "text1",
                        "hOffset": 250,
                        "vOffset": 100,
                        "alignment": "center",
                        "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
                    }
                }}
                """;
This definitely looks better. All of this is already supported in Kotlin, as you can see in its type definitions . So we've seen that Java "inherits" many solutions to its own problems from one of its competitors: Kotlin. We don't know if Oracle responded in time to combat the rise of Kotlin or if it came too late. Personally, I believe that Java is making the right steps forward, even if these changes were somehow initiated by its competitors and may come with some delay.

Conclusion

I think competition is the best thing that ever happened to the Java language. My impression is that otherwise Java would rest on its laurels. Additionally, Java's competitors have shown that a different way of programming is possible, showing how to move forward and avoid outdated and inefficient ways of writing code. Future changes will make Java more powerful than ever, a language adapted to the modern era, a language that wants to evolve.
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION