Java 8
Functional Interface
What is this? A functional interface is an interface that contains one unimplemented (abstract) method. @FunctionalInterface is an optional annotation that is placed above such an interface. Needed to check whether it meets the requirements of a functional interface (having only one abstract method). But as always, we have some caveats: default and static methods do not fall under these requirements. Therefore, there can be several such methods + one abstract one, and the interface will be functional. It may also contain methods of the Object class that do not affect the definition of the interface as functional. I'll add a few words about default and static methods:-
Methods with the default modifier allow you to add new methods to interfaces without breaking their existing implementation.
public interface Something { default void someMethod { System.out.println("Some text......"); } }
Yes, yes, we add the implemented method to the interface, and when implementing this method, you can not override it, but use it as an inherited one. But if a class implements two interfaces with a given method, we will have a compilation error, and if it implements interfaces and inherits a class with a certain identical method, the parent class method will overlap the interface methods and the exception will not work.
-
static methods in an interface work the same as static methods in a class. Don’t forget: you cannot inherit static methods, just as you cannot call a static method from a descendant class.
-
Consumer - takes an argument of type T, returns nothing (void).
Example:
void someMethod(T t);
-
Supplier - takes nothing as input, but returns some value T.
Example:
T someMethod();
-
Function - takes a parameter of type T as input, returns a value of type R.
Example:
R someMethod(T t);
-
UnaryOperator - takes a T argument and returns a value of type T.
Example:
T someMethod(T t);
Predicate - takes some value T as an argument, returns boolean.
Example:boolean someMethod(T t);
Stream
Streams are a way to handle data structures in a functional style. Typically these are collections (but you can use them in other, less common situations). In more understandable language, Stream is a data stream that we process as if working with all the data at the same time, and not brute force, as with for-each. Let's look at a small example. Let's assume we have a set of numbers that we want to filter (less than 50), increase by 5, and output the first 4 numbers from the remaining ones to the console. How would we have done this earlier:List<Integer> list = Arrays.asList(46, 34, 24, 93, 91, 1, 34, 94);
int count = 0;
for (int x : list) {
if (x >= 50) continue;
x += 5;
count++;
if (count > 4) break;
System.out.print(x);
}
There doesn't seem to be much code, and the logic is already a little confusing. Let's see how it will look using the stream:
Stream.of(46, 34, 24, 93, 91, 1, 34, 94)
.filter(x -> x < 50)
.map(x -> x + 5)
.limit(4)
.forEach(System.out::print);
Streams greatly simplify life by reducing the amount of code and making it more readable. For those who want to delve into this topic in more detail, here is a good (I would even say excellent) article on this topic .
Lambda
Perhaps the most important and long-awaited feature is the appearance of lambdas. What is lambda? This is a block of code that can be passed around to different places so it can be executed later as many times as needed. Sounds pretty confusing, doesn't it? Simply put, using lambdas, you can implement a method of a functional interface (a kind of implementation of an anonymous class):Runnable runnable = () -> { System.out.println("I'm running !");};
new Thread(runnable).start();
We implemented the run() method quickly and without unnecessary red tape. And yes: Runnable is a functional interface. I also use lambdas when working with streams (as in the examples with streams above). We won’t go too deep, since you can dive quite deep, I’ll leave a couple of links so that guys who are still diggers at heart can dig deeper:
- article about lambda expressions in Java 8 on Habré
- article about lambda expressions in Java on Alexander Kosarev's blog
foreach
Java 8 has a new foreach that works with a data stream like a stream. Here's an example:List<Integer> someList = Arrays.asList(1, 3, 5, 7, 9);
someList.forEach(x -> System.out.println(x));
(analogous to someList.stream().foreach(…))
Method reference
Reference methods are a new, useful syntax designed to reference existing methods or constructors of Java classes or objects via :: Method references come in four types:-
Link to the designer:
SomeObject obj = SomeObject::new
-
Static method reference:
SomeObject::someStaticMethod
-
A reference to a non-static method of an object of a certain type:
SomeObject::someMethod
-
A reference to a regular (non-static) method of a specific object
obj::someMethod
someList.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
For those who want more information on reference methods:
API Time
There is a new library for working with dates and times - java.time. The new API is similar to any Joda-Time. The most significant sections of this API are:- LocalDate is a specific date, as an example - 2010-01-09;
- LocalTime - time taking into account the time zone - 19:45:55 (analogous to LocalDate);
- LocalDateTime - combo LocalDate + LocalTime - 2020-01-04 15:37:47;
- ZoneId - represents time zones;
- Clock - using this type you can access the current time and date.
- Java and time: part one and two on Habré
- Introduction to Date/Time API in Java 8
Optional
This is a new class in the java.util package , a value wrapper whose trick is that it can also safely contain null . Receiving optional: If we pass nullOptional<String> someOptional = Optional.of("Something");
in Optional.of , we will get our favorite NullPointerException . For such cases they use: - in this method you don’t have to be afraid of null. Next, create an initially empty Optional: To check if it is empty, use: will return true or false to us. Perform a certain action if there is a value, and do nothing if there is no value: A reverse method that returns the passed value if Optional is empty (sort of a backup plan): You can continue for a very, very long time (fortunately, Optional has added methods with both generous hands), but we won’t dwell on this. It’s better for me to leave a couple of links for starters: Optional<String> someOptional = Optional.ofNullable("Something");
Optional<String> someOptional = Optional.empty();
someOptional.isPresent();
someOptional.ifPresent(System.out::println);
System.out.println(someOptional.orElse("Some default content"));
- Java Optional - the father of holivars
- Optional: Schrödinger's Cat in Java 8
- New Optional class in Java 8, not a panacea for NullPointerException
- Features of Java 8: The Ultimate Guide to JavaRush - Part One and Two ;
- New in Java 8 on Habré ;
- Top 10 Java 8 features that people don't talk about ;
- Java 8 Tutorial .
Java 9
So, on September 21, 2017, the world saw JDK 9. This Java 9 comes with a rich set of features. While there are no new language concepts, the new APIs and diagnostic commands will definitely be of interest to developers.JShell (REPL - read-eval-print loop)
This is a Java implementation of an interactive console that is used to test functionality and use different constructs in the console, such as interfaces, classes, enums, operators, etc. To launch JShell, you just need to write jshell in the terminal. Then we can write whatever our imagination allows: Using JShell, you can create top-level methods and use them within the same session. The methods will work just like static methods, except that the static keyword can be omitted. Read more in the Java 9. REPL (JShell) manual .Private
Starting with version 9 of Java, we have the opportunity to use private methods in interfaces (default and static methods, since we simply cannot override others due to insufficient access).private static void someMethod(){}
try-with-resources
The ability to handle Try-With-Resources exceptions has been upgraded:
BufferedReader reader = new BufferedReader(new FileReader("....."));
try (reader2) {
....
}
Modularity ( Jigsaw )
A module is a group of related packages and resources along with a new module descriptor file. This approach is used to loosen the coupling of code. Loose coupling is a key factor for code maintainability and extensibility. Modularity is implemented at different levels:- Programming language.
- Virtual machine.
- Standard java API.
Immutable Collection
In Java 9, it became possible to create and fill a collection with one line, while making it immutable (previously, to create an immutable collection, we needed to create a collection, fill it with data, and call a method, for example, Collections.unmodifiableList). An example of such a creation:List someList = List.of("first","second","third");
Other innovations:
- expanded Optional (new methods added);
- the ProcessHandle and ProcessHandle interfaces appeared to control the actions of the operating system;
- G1 - default garbage collector;
- HTTP client with support for both HTTP/2 protocols and WebSocket;
- expanded Stream;
- added Reactive Streams API framework (for reactive programming);
- Review of Java 9 on Habré
- Java 9. What's new?
- Java 9: New Features
- Java 9 - Have you upgraded yet? No? And it is not necessary ...!?
- Sander Mak on the transition to Java modules
Java 10
So, six months after the release of Java 9, in March 2018 (I remember it like yesterday), Java 10 came onto the scene.var
Now we don't have to provide a data type. We mark the message as var and the compiler determines the type of the message by the type of the initializer present on the right. This feature is only available for local variables with an initializer: it cannot be used for method arguments, return types, etc., since there is no initializer to be able to define the type. Example var (for type String):var message = "Some message…..";
System.out.println(message);
var is not a keyword: it is essentially a reserved type name, just like int . The benefit of var is great: type declarations take up a lot of attention without bringing any benefit, and this feature will save time. But at the same time, if a variable is obtained from a long chain of methods, the code becomes less readable, since it is immediately unclear what kind of object lies there. Dedicated to those who want to become more familiar with this functionality:
- Java 10 LocalVariable Type-Inference
- First contact with "var" in Java 10
- 26 Tips for Using the var Type in Java
JIT compiler (GraalVM)
Without further ado, let me remind you that when you run the javac command, the Java application is compiled from Java code into JVM bytecode, which is the binary representation of the application. But a regular computer processor cannot simply execute the JVM bytecode. For your JVM program to work, you need another compiler for this bytecode, which is converted into machine code that the processor is already able to use. Compared to javac, this compiler is much more complex, but also produces higher quality machine code. Currently, OpenJDK contains the HotSpot virtual machine, which in turn has two main JIT compilers. The first, C1 ( client compiler ), is designed for higher speed operation, but code optimization suffers. The second is C2 (server compiler). The execution speed suffers, but the code is more optimized. When is which one used? C1 is great for desktop applications where long JIT pauses are undesirable, and C2 is great for long-running server programs where spending more time on compilation is quite bearable. Multi-level compilation is when the compilation first goes through C1, and the result goes through C2 (used for greater optimization). GraalVM is a project created to completely replace HotSpot. We can think of Graal as several related projects: a new JIT compiler for HotSpot and a new polyglot virtual machine. The peculiarity of this JIT compiler is that it is written in Java. The advantage of the Graal compiler is safety, that is, not crashes, but exceptions, not memory leaks. We will also have good IDE support, and we will be able to use debuggers, profilers or other convenient tools. In addition, the compiler may well be independent of HotSpot, and it will be able to create a faster JIT-compiled version of itself. For diggers:- Deep Dive into the New Java JIT Compiler
- Graal: How to use the new JVM JIT compiler in real life
- How Graal works - Java JVM JIT compiler
Parallel G1
The G1 garbage collector is certainly cool, no doubt about it, but it also has a weak point: it performs a single-threaded full GC cycle. At a time when you need all the power of hardware you can muster to find unused objects, we are limited to a single thread. Java 10 fixed this. Now the GC now works with all the resources we add to it (that is, it becomes multi-threaded). To achieve this, the language developers have improved the isolation of the main sources from GC, creating a nice clean interface for GC. The developers of this cuteness, OpenJDK, had to specifically clean up the dump in the code in order not only to simplify the creation of new GCs as much as possible, but also to make it possible to quickly disable unnecessary GCs from the assembly. One of the main criteria for success is the absence of a drawdown in operating speed after all these improvements. Let's look also: Other innovations:- A clean Garbage-Collector Interface is introduced. This improves the isolation of source code from different garbage collectors, making it possible to integrate alternative collectors quickly and painlessly;
- Combining JDK sources into one repository;
- Collections received a new method - copyOf (Collection) , which returns an immutable copy of this collection;
- Optional (and its variants) has a new method .orElseThrow() ;
- From now on, JVMs are aware that they are running in a Docker container and will retrieve container-specific configuration rather than querying the operating system itself.
- Guide to Java 10
- 10 JDK 10 features Java developers should know
- What's New in Java 10: Part One and Two
GO TO FULL VERSION