1. Performance improvement
Every time the JDK version is upgraded, the JVM speed will be improved. The performance improvement of jdk9-11 JVM is mainly reflected in garbage collection;
garbage collector :
- The default configuration of java8 is UseParallelGC. The default value of the virtual machine running in Server mode. Use the collector combination of Parallel Scavenge + Serial Old for memory reclamation. Many projects use useonemarksweepgc. Use the collector combination of ParNew + CMS + Serial Old for memory reclamation. The Serial Old collector will be used as a backup collector after the CMS collector fails in concurrent mode. CMS is removed from java14;
//**View GC configuration java -XX:+PrintCommandLineFlags -version
- The default configuration of java9 is UseG1GC. Use G1 collector for memory recovery;
- java10 improves G1 collector, allows parallel Full GC, and improves G1 latency. G1 will try to avoid Full GC, but Full GC will still appear. java10 uses a parallel mark clear compress algorithm. The number of threads can be configured with - XX:ParallelGCThreads.
- Java 11 introduces the configuration of useepsilon GC. Use Epsilon garbage collector for memory reclamation. It is an inoperative garbage collector that handles memory allocation but does not implement any actual memory recycling mechanism. Once the available heap memory is used up, the JVM will exit;
- Java 11 introduces the configuration UseZGC. Use the ZGC garbage collector for memory reclamation. It is a scalable low latency garbage collector, but it is still experimental. It is not recommended to use the production environment;
2. Grammatical features
java9
Set factory method
Set factory method (creating immutable sets) simplifies the code of creating sets, especially Map;
public class MyCollections { //**Simplified code collection public static void test() { List list = List.of(1, 2, 3); System.out.println(list); Set set = Set.of(1, 2, 3); System.out.println(set); Map map = Map.of("key1", "value1", "key2", "value2"); System.out.println(map); } }
Completabilefuture new method
public class MyCompletableFuture { public static void main(String[] args) throws Exception { //**Factory method, which returns the completable future completed abnormally CompletableFuture<String> future1 = CompletableFuture.failedFuture(new RuntimeException("error")); //future1.get(); CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(5); } catch (Exception ignored) {} return "pings1"; }); //**If future2 can be completed within a given time, the return value of future2 will be returned; otherwise, the default value will be returned //CompletableFuture<String> future3 = future2.completeOnTimeout("pings2", 4, TimeUnit.SECONDS); //System.out.println(future3.get()); //**If future2 can be completed within a given time, the return value of future2 will be returned; otherwise, it will be completed with TimeoutException CompletableFuture<String> future4 = future2.orTimeout(4, TimeUnit.SECONDS); System.out.println(future4.get()); } }
Generic improvement
public class MyGenerics { interface MyClass<T> { T get(); T get1(); } public static void main(String[] args) { //**Anonymous class generic inference MyClass<String> myClass = new MyClass<>() { @Override public String get() { return "pings"; } @Override public String get1() { return "pings1"; } }; System.out.println(myClass.get()); } }
Interface private method
Now the difference between interface and abstract method:
- Abstract methods can define properties of various scopes, and interfaces can only define public static properties
- Abstract methods can define methods of various scopes, and interfaces can only define the default implementation of private and public methods
public interface MyInterface { private void b() { //**You can use this keyword System.out.println("b: " + this.getClass().getSimpleName()); } class MyInterfaceImpl implements MyInterface { } static void main(String[] args) { MyInterface myInterface = new MyInterfaceImpl(); myInterface.b(); } }
Optional new method
public class MyOptional { public static void main(String[] args) { //**Optional.stream List<Optional<String>> list = List.of(Optional.of("A"), Optional.empty(), Optional.of("B")); list.stream().flatMap(Optional::stream).forEach(System.out::println); //**Optional.ifPresentOrElse List<Integer> list1 = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Optional<Integer> optional = list1.stream().filter(i -> i > 5).findAny(); optional.ifPresentOrElse(System.out::println, () -> { throw new IllegalArgumentException(); }); //**Optional.or, which is different from orElseGet: the orElseGet parameter returns the type of optional wrapper, and or still returns optional optional = list1.stream().filter(i -> i > 10).findAny(); Optional optional1 = optional.or(() -> Optional.of(100)); int rst = optional.orElseGet(() -> 100); System.out.println(optional1.get()); System.out.println(rst); } }
New method of stream
public class MyStream { public static void main(String[] args) { List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); //**takeWhile, returns the element that matches the expression until it does not meet the expression for the first time List<Integer> list1 = list.stream().takeWhile(i -> i < 5).collect(toList()); System.out.println(list1); //**dropWhile, delete the elements of the expression until the expression is not satisfied for the first time List<Integer> list2 = list.stream().dropWhile(i -> i < 5 || i > 9).collect(toList()); System.out.println(list2); //**for(int i = 1; i < 10; i +=2) IntStream.iterate(1, x -> x < 10, x -> x + 2).forEach(System.out::println); Stream.iterate("ping", s -> s.length() < 10, s -> s = s + "1").forEach(System.out::println); //**The element does not support list, so I don't know what the actual use is Stream.ofNullable(null).forEach(System.out::println); //**This method can avoid null pointer when list3 is null, which still feels useless List list3 = null; List<Integer> list4 = List.of(1, 2); Stream.ofNullable(list3).flatMap(List::stream).forEach(System.out::println); Stream.ofNullable(list4).flatMap(List::stream).forEach(System.out::println); } }
Try with resources improvement
public class MyTryWithResources { public static void main(String[] args) throws IOException { Reader reader = new StringReader("pings"); BufferedReader br = new BufferedReader(reader); //**Compared with the improvement of jdk7, the external variable br can be referenced. Br must be final try (reader; br) { System.out.println(br.readLine()); } } }
java10
Collection copyOf static method
public class MyCollections { //**The set factory method simplifies the code for creating sets public static void test() { var list = List.of(1, 2, 3); var newList = List.copyOf(list); System.out.println(newList); var map = Map.of("key1", "value1", "key2", "value2"); System.out.println(Map.copyOf(map)); } public static void main(String[] args) { test(); } }
Local variable type inference
var is introduced as the inference identifier of local variable type, which is only applicable to local variables and cannot be used for method formal parameters, constructor formal parameters, method return type, catch formal parameters or any other type of variable declaration;
public class MyVar { public static void main(String[] args) { var ss = 123; //**The type of generics can be inferred var list = List.of(1, 2, 3, 4); var newList = list.stream().map(Integer::getClass).collect(toList()); System.out.println(newList); } }
java11
String addition method
public class MyString { public static void main(String[] args) { String str = "pings"; boolean isBlank = str.isBlank(); //**Judge whether the string is blank System.out.println(isBlank); //str = null; //System.out.println(str.isBlank()); //** Can't judge non null, I thought I could replace stringutils Isblank() method boolean isEmpty = str.isEmpty(); //Judge whether the string is empty System.out.println(isEmpty); String result1 = str.strip(); //**First blank String result2 = str.stripTrailing(); //**Remove trailing blanks String result3 = str.stripLeading(); //**Remove header blank System.out.println("12".repeat(5)); //**Copy string several times str.lines().forEach(System.out::println); //**Read by line } }
Local variable type inference enhancement
var can be referenced to the parameters of lambda expression;
public class MyVar { public static void main(String[] args) { //**var can be referenced to the parameters of lambda expression. Originally, the parameters of lambda expression can be written without type. What's the use of writing in this way Consumer<String> consumer1 = (var t) -> System.out.println(t.toUpperCase()); consumer1.accept("pings"); //**If you want to annotate the parameters of a lambda expression, you must have a type //**The function is to define the parameter type when annotating the parameters of lambda expression Consumer<String> consumer2 = (@Deprecated var t) -> System.out.println(t.toUpperCase()); consumer2.accept("pings"); } }
HttpClient
public class MyHttpClient { public static void test() throws Exception { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder(URI.create("http://www.baidu.com")).build(); HttpResponse.BodyHandler<String> handler = HttpResponse.BodyHandlers.ofString(); //**Synchronous call //HttpResponse<String> response = client.send(request, handler); //String body = response.body(); //**Asynchronous call CompletableFuture<HttpResponse<String>> response = client.sendAsync(request, handler); HttpResponse<String> result = response.get(); String body = result.body(); System.out.println(body); } }