New Features of Java 8 and new features of Java 8
1. Interface Improvement
A. Static methods can be defined in the interface
B. More importantly, the method in the interface can be modified with default to add the method body.
2. Why cannot I use the default method to override the equals, hashcode, and toString methods?
That is, the interface cannot provide default implementation for any methods of the Object class. If a class implements a method, it always takes precedence over the default implementation. Once the instances of all interfaces are subclasses of objects, all interface instances have non-default implementations for equals, hashCode, and toString. Therefore, a default version on the interface is useless and will not be compiled.
3. functional interfaces
The core concept is functional interfaces. If an interface defines a unique abstract method, this interface becomes a functional interface. For example, java. lang. Runnable is a functional interface, because it defines only one abstract method:
public abstract void run();
What is a functional interface? There are two situations: 1. The interface has only one abstract method, abstract modification 2. The interface has only one abstract method, abstract modification. At the same time, there are multiple default methods, because the default method is modified by default, not abstract.
At the same time, a new Annotation: @ FunctionalInterface is introduced. You can put it in front of an interface, indicating that this interface is a functional interface. The interfaces added with it won't be compiled unless you try to turn it into a functional interface. It is a bit like @ Override, which declares an intent to avoid mistakes.
4. Lambdas
A very valuable attribute of a functional interface is that they can be instantiated using lambdas. Here are some lambdas examples:
On the left is a comma-separated input list of the specified type, and on the right is a code block with return:
(int x, int y) -> { return x + y; }
On the left is the comma-separated input list of the derivation type, and on the right is the return value:
(x, y) -> x + y
The left side is a single parameter of the derivation type, and the right side is a return value:
x -> x * x
There is no input on the left (official name: "burger arrow"), and a value is returned on the right:
() -> x
The left side is a single parameter of the derivation type, and the right side is a code block with no return value (return void ):
x -> { System.out.println(x); }
Static Method reference:
String::valueOf
Non-static method reference:
Object::toString
Inherited function reference:
x::toString
Constructor reference:
ArrayList::new
You can come up with some function reference formats as shorthand for other lambda formats.
Method reference |
Equivalent lambda expressions |
|
String: valueOf |
|
X-> String. valueOf (x) |
Object: toString |
|
X-> x. toString () |
X: toString |
|
()-> X. toString () |
ArrayList: new |
|
()-> New ArrayList <> () |
Of course, methods in Java can be overloaded. Class can have multiple methods with the same name but different parameters. This is also valid for the constructor. ArrayList: new can point to any of its three constructor methods. Decide which method to use based on the function interface in use.
A lambda interface is compatible with a given functional interface when the "appearance" matches. Through "appearance", I point to the input and output types and declarations to check for exceptions.
Two examples are provided:
Comparator<String> c = (a, b) -> Integer.compare(a.length(), b.length());
The compare method of a Comparator <String> requires two arguments, and an int is returned. This is consistent with that on the right side of lambda, so this task is valid.
Runnable r = () -> { System.out.println("Running!"); }
A Runnable run method does not require a parameter or return a value. This is the same as that on the right side of lambda, so the task is valid.
It is also important to check for exceptions (if any) in the signature of the abstract method. If a function interface declares an exception in its signature, lambda can only throw a checked exception.
5. captured and non-captured Lanbdas expressions
When a Lambda expression accesses a non-static variable or object defined in the Lambda expression in vitro, this Lambda expression is called "captured ". For example, the lambda expression below captures the variable x:
int x = 5; return y -> x + y;
To ensure that the lambda expression declaration is correct, the variables captured by the lambda expression must be "valid final. So either they need to be marked with final modifiers, or they cannot be changed after being assigned a value.
Whether Lambda expressions are captured is quietly related to performance. A non-capturing lambda is generally more efficient than capturing, although there is no written specification (as far as I know), and it cannot be expected to do anything for the correctness of the program, non-captured lambda only needs to be calculated once. then, a unique instance is returned every time it is used. The captured lambda expression needs to be re-computed every time it is used. From the current implementation perspective, it is similar to instantiating an instance of an anonymous internal class.
6. Miscellaneous
What lambdas does not do
You should remember that there are some features not provided by lambdas. For Java 8, they are taken into account, but not included, due to simplification and time constraints.
Non-final * variable capture-if a variable is assigned a new value, it cannot be used in lambda. The "final" keyword is not required, but the variable must be "valid final" (discussed earlier ). This code will not be compiled:
int count = 0;List<String> strings = Arrays.asList("a", "b", "c");strings.forEach(s -> { count++; // error: can't modify the value of count });
Transparency of exceptions-if a detected exception may be thrown from inside lambda, the functional interface must also declare that the detected exception can be thrown. Such exceptions are not distributed to the methods they contain. This code will not be compiled:
void appendAll(Iterable<String> values, Appendable out) throws IOException { // doesn't help with the error values.forEach(s -> { out.append(s); // error: can't throw IOException here // Consumer.accept(T) doesn't allow it });}
In this way, you can define your own functional interfaces, extend the Consumer, and throw an IOException like RuntimeException. I tried to write it out in code, but I found it confusing and worthwhile.
Break (early return)-in the preceding forEach example, the traditional method of continuation may be implemented by placing "return;" in lambda. However, there is no way to interrupt the loop or return a value from lambda through the result of the Inclusion Method. For example:
final String secret = "foo"; boolean containsSecret(Iterable<String> values) { values.forEach(s -> { if (secret.equals(s)) { ??? // want to end the loop and return true, but can't } });}
Read more about these questions and read the instructions written by Brian Goetz: Respond to "verified exceptions" super0555 in Block <T>.
Other translated versions (1) why abstract classes cannot be instantiated by using lambda
Abstract class, even if only one abstract method is declared, lambda cannot be used for instantiation.
The following two examples of Ordering and CacheLoader classes have an abstract method, which is taken from the Guava library. Isn't it a pleasure to declare their instances and use lambda expressions like this?
Ordering <String> order = (a, B)-> ...;
CacheLoader<String, String> loader = (key) -> ...;
The most common debate caused by this is that it will increase the difficulty of reading lambda. Instantiating an abstract class in this way will cause the execution of hidden code: the constructor of the abstract class.
Another reason is that it throws possible Optimization of lambda expressions. In the future, it may be the case that lambda expressions will not compute to the object instance. Letting users declare abstract classes with lambda will impede such optimization.
In addition, there is a simple solution. In fact, the above two instance classes from the Guava library have proved this method. Add a factory method to convert lambda to an instance.
Ordering<String> order = Ordering.from((a, b) -> ...);CacheLoader<String, String> loader = CacheLoader.from((key) -> ...);
For more information, see the description by Brian Goetz: response to "Allow lambdas to implement abstract classes ".
Java. util. function
Package Overview: java. util. function
As an early proof of Comparator and Runnable, the interfaces defined in JDK happen to be compatible with lambdas expressions as function interfaces. In the same way, you can define any function interface or third-party library in your own code.
However, there are specific forms of function interfaces, which are extensive and common and do not exist in the previous JD card. A large number of interfaces are added to the new java. util. function package. Below are some of them:
- Function <T, R>-T is used as the input, and the returned R is used as the output.
- Predicate <T>-T is used as the input, and the returned boolean value is used as the output.
- Consumer <T>-T is used as the input to execute an action but no return value.
- Supplier <T>-no input. T is returned.
- BinaryOperator <T>-two t s are used as the input, and one T is returned as the output, which is useful for the "reduce" operation.
These most primitive features also exist. They are provided in int, long, and double ways. For example:
- IntConsumer-uses int as the input to execute an action without returning a value
There are some performance reasons, which are mainly explained to avoid packing and unpacking during input or output.
You should remember that there are some features not provided by lambdas. For Java 8, they are taken into account, but not included, due to simplification and time constraints.
Non-final * variable capture-if a variable is assigned a new value, it cannot be used in lambda. The "final" keyword is not required, but the variable must be "valid final" (discussed earlier ). This code will not be compiled:
int count = 0;List<String> strings = Arrays.asList("a", "b", "c");strings.forEach(s -> { count++; // error: can't modify the value of count });
Transparency of exceptions-if a detected exception may be thrown from inside lambda, the functional interface must also declare that the detected exception can be thrown. Such exceptions are not distributed to the methods they contain. This code will not be compiled:
void appendAll(Iterable<String> values, Appendable out) throws IOException { // doesn't help with the error values.forEach(s -> { out.append(s); // error: can't throw IOException here // Consumer.accept(T) doesn't allow it });}
In this way, you can define your own functional interfaces, extend the Consumer, and throw an IOException like RuntimeException. I tried to write it out in code, but I found it confusing and worthwhile.
Break (early return)-in the preceding forEach example, the traditional method of continuation may be implemented by placing "return;" in lambda. However, there is no way to interrupt the loop or return a value from lambda through the result of the Inclusion Method. For example:
final String secret = "foo"; boolean containsSecret(Iterable<String> values) { values.forEach(s -> { if (secret.equals(s)) { ??? // want to end the loop and return true, but can't } });}
Read more about these questions and read the instructions written by Brian Goetz: Respond to "verified exceptions" in Block <T>"
Super0555 was translated well by four people four years ago! Other translated versions (1) why abstract classes cannot be instantiated by using lambda
Abstract class, even if only one abstract method is declared, lambda cannot be used for instantiation.
The following two examples of Ordering and CacheLoader classes have an abstract method, which is taken from the Guava library. Isn't it a pleasure to declare their instances and use lambda expressions like this?
Ordering <String> order = (a, B)-> ...;
CacheLoader<String, String> loader = (key) -> ...;
The most common debate caused by this is that it will increase the difficulty of reading lambda. Instantiating an abstract class in this way will cause the execution of hidden code: the constructor of the abstract class.
Another reason is that it throws possible Optimization of lambda expressions. In the future, it may be the case that lambda expressions will not compute to the object instance. Letting users declare abstract classes with lambda will impede such optimization.
In addition, there is a simple solution. In fact, the above two instance classes from the Guava library have proved this method. Add a factory method to convert lambda to an instance.
Ordering<String> order = Ordering.from((a, b) -> ...);CacheLoader<String, String> loader = CacheLoader.from((key) -> ...);
For more information, see the description by Brian Goetz: response to "Allow lambdas to implement abstract classes ".
When PM was translated, it was a good translation for two people at the top four years ago! Java. util. function
Package Overview: java. util. function
As an early proof of Comparator and Runnable, the interfaces defined in JDK happen to be compatible with lambdas expressions as function interfaces. In the same way, you can define any function interface or third-party library in your own code.
However, there are specific forms of function interfaces, which are extensive and common and do not exist in the previous JD card. A large number of interfaces are added to the new java. util. function package. Below are some of them:
- Function <T, R>-T is used as the input, and the returned R is used as the output.
- Predicate <T>-T is used as the input, and the returned boolean value is used as the output.
- Consumer <T>-T is used as the input to execute an action but no return value.
- Supplier <T>-no input. T is returned.
- BinaryOperator <T>-two t s are used as the input, and one T is returned as the output, which is useful for the "reduce" operation.
These most primitive features also exist. They are provided in int, long, and double ways. For example:
- IntConsumer-uses int as the input to execute an action without returning a value
There are some performance reasons, which are mainly explained to avoid packing and unpacking during input or output.
When PM was translated, it was a good translation for two people at the top four years ago!
All translations in this article are only used for learning and communication purposes. For reprinting, please be sure to indicate the author's translator, source, and link to this Article. Our translation work complies with the CC protocol, if your rights and interests are violated in our work, please contact us in time for comment (85)