JDK 8 New Features
Related features in Java 5
Some common syntax has been introduced in Java 5 and is often used together when learning JDK 8 features.
enumeration
Enumeration is a special type used to represent a fixed set of constants. Enumeration constants must be written at the beginning of the enumeration body.
public enum Week {
MON("星期一"),
TUE("星期二"),
WED("星期三"),
THU("星期四"),
FRI("星期五"),
SAT("星期六"),
SUN("星期日");
private final String chineseName;
Week(String chineseName) {
this.chineseName = chineseName;
}
public String getChineseName() {
return chineseName;
}
}Enumeration constants cannot be added or deleted at will after type definition is completed. The properties of enumerated objects are usually designed to be immutable.
variable parameters
Variable parameters allow you to pass in an indefinite number of arguments of the same type when calling a method. A method can have at most one variable parameter, and it must be at the end of the parameter list.
public class Test {
public static void method(String text, int... numbers) {
System.out.println(text);
for (int number : numbers) {
System.out.println(number);
}
}
public static void main(String[] args) {
method("abc", 1, 2, 3, 4);
}
}Within a method, variable parameters are used as arrays.
Main features of JDK 8
Interface default and static methods
JDK 8 allows interfaces to define default and static methods. The default method is decorated with default and is mainly used to be compatible with existing implementation classes when extending interfaces.
public interface ITest {
void method();
default void method1() {
System.out.println("默认方法");
}
static void method2() {
System.out.println("静态方法");
}
}functional interface
An interface that has only one abstract method is called a functional interface. Functional interfaces can contain default methods and static methods because they are not abstract methods.
The @FunctionalInterface annotation is used to verify whether the interface meets the requirements of a functional interface.
@FunctionalInterface
public interface ITest {
void method();
default void method1() {
System.out.println("默认方法");
}
}
Lambda expressions
Lambda expressions are used to succinctly represent the implementation of functional interface abstraction methods. Their basic structure is:
(参数列表) -> { 方法体 }
For example, an implementation of Runnable can be provided directly when creating a thread:
new Thread(() -> {
System.out.println("执行 run 方法");
}).start();
Parameter types can usually be inferred by the compiler. When there is only one statement in the method body, the braces can be omitted; if the only statement is a return expression, return can also be omitted.
Arrays.sort(strings, (s1, s2) -> s1.length() - s2.length());
Lambda expressions are written succinctly, but they must appear where functional interface objects are required.
method reference
Method references can be used when an existing method can complete the operations described by a Lambda expression. Common forms are as follows:
类名::静态方法
类名::实例方法
对象::实例方法
类名::new
Whether a method reference can be used depends on whether the abstract method parameters and return values of the target functional interface are compatible with the referenced method. The method names are not required to be the same.
List<String> list = new ArrayList<>();
Collections.addAll(list, "ab", "cd", "ef");
list.forEach(value -> System.out.println(value));
list.forEach(System.out::println);
list.forEach(Test::upperPrintln);
public class Test {
public static void upperPrintln(String value) {
String result = String.valueOf(value.charAt(0)).toUpperCase()
+ value.substring(1);
System.out.println(result);
}
}
Stream stream
Stream is used to perform operations such as filtering, mapping, sorting, and aggregation on data sequences. It does not store data directly and usually uses a collection or array as the data source.
traverse element
forEach() is a termination operation used to consume elements in the stream.
List<Integer> list = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
list.stream().forEach(System.out::println);
list.parallelStream().forEach(System.out::println);
The output order of parallel streams is not necessarily the same as the original set.
mapping element
map() converts each element to another value and generates a new stream.
list.stream()
.map(number -> number * 2)
.forEach(System.out::println);
Filtering and interception
filter() retains elements based on conditions, and limit() limits the number of results. Depending on the order of operations, the results may be different.
list.stream()
.limit(3)
.filter(number -> number > 2)
.forEach(System.out::println);
list.stream()
.filter(number -> number > 2)
.limit(3)
.forEach(System.out::println);Sort and de-duplication
sorted() is used for sorting and distinct() is used for deduplication removal.
list.stream()
.sorted()
.distinct()
.forEach(System.out::println);
gather result
collect() can collect stream processing results into new collections or strings.
List<Integer> oddNumbers = list.stream()
.filter(number -> (number & 1) == 1)
.collect(Collectors.toList());
System.out.println(oddNumbers);
List<String> words = Arrays.asList("a", "b", "c");
String result = words.stream()
.collect(Collectors.joining("-"));
System.out.println(result);statistical quantity
count() returns the number of elements in the flow.
long count = list.stream()
.filter(number -> number > 2)
.count();
System.out.println(count);
If you enjoyed this, leave a comment~