New features of Java 5, Java 6, Java 7, Java 8

Keywords: Java Lambda jvm JDK

Java5:

Generics:
After referencing generics, it allows you to specify the type of elements in a collection, eliminates mandatory type conversion, and has the advantage of type checking at compile time.

As parameters and return values, Generic is the cornerstone of vararg, annotation, enumeration, collection.

A. Type Safety

When you abandon Lists and Maps, add elements to them using List < T >, Map < K, V > or use Iterator < T > traversal, you can check out type errors at compile time.

Type is added to B, method parameters and return values

Discard List and Map and use List < T >, Map < K, V >

C. No need for type conversion

          List<String> list=new ArrayList<String>();

       String str=list.get(i);

D, type wildcard "?"

Assuming a method of printing elements in List < T > printList, we hope that List < T > of any type of T can be printed:

Code:

  1. public void printList(List<?> list,PrintStream out)throws IOException{  
  2. for(Iterator<?> i=list.iterator();i.hasNext();){  
  3. System.out.println(i.next.toString());  
  4. }  
  5.   
  6. }  

If wildcards? Let's make our parameter types too broad. We can modify List<?>, Iterator<?> to

List <? Extends Number >, Iterator <? Extends Number > Limit it.

2. Enumeration type:

3. autoboxing & unboxing:

Simply put, automatic type conversion.

Automatic Packing: Basic Types are automatically converted to Packaging Classes (int-Integer)

Automatic unpacking: Packaging class automatically converts to basic type (Integer-int)

4. Variable parameter varargs(varargs number of arguments)

When the parameter types are the same, the overloaded functions are merged together.

For example: public void test(object... objs){

for(Object obj:objs){

System.out.println(obj);

}

}

5. Annotations is metadata in java

Three standard annotation s predefined in A and Tiger

           a ,Override

Indicate that a method overrides a method of superclass and fails to compile when the method name you want to override is misspelled.

           b,Deprecated

Indicate that the use of a method or element type is blocked and that subclasses will not be able to override the method

           c,SupressWarnings

Close compile-time warnings for class, method, field, variable initialization, such as @SuppressWarnings("unchecked") to remove compile-time warnings if List does not use Generic.

Custom annotation

          public @interface Marked{}

     C,meta-annotation

Or annotation

All four standard meta-annotation s are defined in the java.lang.annotaion package:
          a, Target
Specify which program units the defined annotation can be used on
If Target is not specified, this annotation can be used on any program unit
Code

  1. @Retention(RetentionPolicy.RUNTIME)    
  2. @Target({ ElementType.FIELD, ElementType.METHOD })    
  3. public @interface RejectEmpty {    
  4.    /** hint title used in error message */    
  5.  String value() default "";    
  6. }    
  7.    
  8. @Retention(RetentionPolicy.RUNTIME)    
  9. @Target( { ElementType.FIELD, ElementType.METHOD })    
  10. public @interface AcceptInt {    
  11.  int min() default Integer.MIN_VALUE;    
  12. int max() default Integer.MAX_VALUE;    
  13.   String hint() default "";    
  14. }  

    b, Retention
Indicate how Java compile-time treats annotation
annotation can be discarded at compile time or retained in compiled class files
When annotation is retained, it also specifies whether the annotation will be read when the JVM loads the class
Code

  1. @Retention(RetentionPolicy.SOURCE)  //Annotation will be discarded at compile time.
  2. public @interface TODO1 {}    
  3.  @Retention(RetentionPolicy.CLASS)   //Annotation remains in the class file, but is ignored by the JVM.
  4.  public @interface TODO2 {}    
  5. @Retention(RetentionPolicy.RUNTIME) //Annotation is kept in the class file and read by JVM.
  6.  public @interface TODO3 {}    

       c, Documented
Indicate that a defined annotation is considered one of the public API s of a familiar program unit
Annotation annotated by @Documented will be displayed in javadoc, which works when annotation has an impact on the elements it annotates when used by the client
       d, Inherited
The meta-annotation is applied to the annotation type of the target class, and the annotation annotated class automatically inherits the annotation of the parent class.
D, Annotation's Reflection
We found that java.lang.Class has many methods related to Annotation reflection, such as getAnnotations, is Annotation present.
We can use Annotation reflection to do many things, such as custom Annotation to do Model object validation
Code
  1.  @Retention(RetentionPolicy.RUNTIME)    
  2.  @Target({ ElementType.FIELD, ElementType.METHOD })    
  3. public @interface RejectEmpty {    
  4.    /** hint title used in error message */    
  5.   String value() default "";    
  6.  }    
  7.      
  8.  @Retention(RetentionPolicy.RUNTIME)    
  9. @Target( { ElementType.FIELD, ElementType.METHOD })    
  10.  public @interface AcceptInt {    
  11.      int min() default Integer.MIN_VALUE;    
  12.     int max() default Integer.MAX_VALUE;    
  13.  String hint() default "";    
  14. }    
Use @RejectEmpty and @AcceptInt to annotate the field of our Model, and then use reflection to validate the Model

6. New iteration statement (for(int: n:numbers)

7. static import

8. New formatting method (java.util.Formatter)

formatter.format("Remaining account balance: $%.2f", balance);

9. New thread model and concurrent library Thread Framework

Replacer of HashMap ConcurrentHashMap Alternatives to Array List CopyOnWriteArrayList
Using some classes in the java.util.concurrent package for large concurrent reads will satisfy you with BlockingQueue, Callable, Executor, Semaphore...

Java6:

1. Introducing a new framework to support script engine

2. UI Enhancement

3. Enhancement of Web Service Support (JAX-WS2.0 and JAXB 2.0)

4. A series of new security-related enhancements

5,JDBC4.0

6,Compiler API

7. General Annotations Support

Java7:

1. Strings can be used in switch

  1. String s = "test";   
  2. switch (s) {   
  3. case "test" :   
  4. System.out.println("test");   
  5. case "test1" :   
  6. System.out.println("test1");   
  7. break ;   
  8. default :   
  9. System.out.println("break");   
  10. break ;   
  11. }  

2. Use List < String > tempList = new ArrayList <>(); that is, automatic inference of generic instantiation type

3. Grammatically support collections, not necessarily arrays

final List<Integer> piDigits = [ 1,2,3,4,5,8 ]; 
4. Adding tools and methods to get environmental information
  1. File System.getJavaIoTempDir() //IO Temporary Folder  
  2. File System.getJavaHomeDir() //JRE installation directory  
  3. File System.getUserHomeDir() //Current user directory  
  4. File System.getUserDir() //Directory 5 where the java process was started  

5.Boolean type inversion, null pointer security, participation in bit operations
  1. Boolean Booleans.negate(Boolean booleanObj)  
  2. True => False , False => True, Null => Null  
  3. boolean Booleans.and(boolean[] array)  
  4. boolean Booleans.or(boolean[] array)  
  5. boolean Booleans.xor(boolean[] array)  
  6. boolean Booleans.and(Boolean[] array)  
  7. boolean Booleans.or(Boolean[] array)  
  8. boolean Booleans.xor(Boolean[] array)  



6. equals between two char s
boolean Character.equalsIgnoreCase(char ch1, char ch2)

7. Safe addition, subtraction, multiplication and division
  1. int Math.safeToInt(long value)  
  2. int Math.safeNegate(int value)  
  3. long Math.safeSubtract(long value1, int value2)  
  4. long Math.safeSubtract(long value1, long value2)  
  5. int Math.safeMultiply(int value1, int value2)  
  6. long Math.safeMultiply(long value1, int value2)  
  7. long Math.safeMultiply(long value1, long value2)  
  8. long Math.safeNegate(long value)  
  9. int Math.safeAdd(int value1, int value2)  
  10. long Math.safeAdd(long value1, int value2)  
  11. long Math.safeAdd(long value1, long value2)  
  12. int Math.safeSubtract(int value1, int value2)  

8. The map set supports concurrent requests and can be written as Map map = {name: `xxx', age: 18};

JAVA8:

New features of Java 8 are listed one by one and will use simple code examples to guide you how to use default interface methods, lambda expressions, method references, and multiple Annotation s. Later you will learn about the latest API improvements, such as streams, functional interfaces, Map s, and new date APIs.

Default Method of Interface

Java 8 allows us to add a non-abstract method implementation to the interface, using only the default keyword. This feature is also called an extension method. Examples are as follows:

  1. interface Formula {  
  2.     double calculate(int a);    
  3.      default double sqrt(int a) {  
  4.         return Math.sqrt(a);  
  5.     }  
  6. }   
The Formula interface defines the sqrt method besides the calculate method. The subclass that implements the Formula interface only needs to implement a calculate method. The default method sqrt will be used directly on the subclass.
  1. Formula formula = new Formula() {  
  2.     @Override  
  3.     public double calculate(int a) {  
  4.         return sqrt(a * 100);  
  5.     }  
  6. };    
  7.  formula.calculate(100);     // 100.0  
  8. formula.sqrt(16);           // 4.0   
formula is implemented as an example of an anonymous class. The code is very easy to understand. Six lines of code implement the calculation of sqrt(a * 100). In the next section, we will see a simpler way to implement a unilateral interface. Translator's Note: There is only single inheritance in Java. If a class is to be given new features, it is usually implemented by using interfaces. In C++ multi-inheritance is supported, allowing one subclass to have multiple parent classes'interfaces and functions at the same time. In other languages, the method of making one class have other reusable codes at the same time is called mixin. New Java This new version of 8 is closer to Scala's trait in terms of compiler implementation. There is also a concept called extension method in C #, which allows existing type extension methods to be semantically different from that in Java 8.

2. Lambda expression

First look at how strings are arranged in older versions of Java:

  1. List<String> names = Arrays.asList("peter""anna""mike""xenia");    
  2.  Collections.sort(names, new Comparator<String>() {  
  3.     @Override  
  4.     public int compare(String a, String b) {  
  5.         return b.compareTo(a);  
  6.     }  
  7. });   
Simply pass in a List object and a comparator to the static method Collections.sort in the specified order. Typically, you create an anonymous comparator object and pass it to the sort method. In Java 8, you don't need to use this traditional way of anonymous objects. Java 8 provides a more concise syntax, lambda expressions:
  1. Collections.sort(names, (String a, String b) -> {  
  2.     return b.compareTo(a);  
  3. });  
As you can see, the code becomes more segmented and readable, but it can actually be written shorter:
  1. Collections.sort(names, (String a, String b) -> b.compareTo(a));  

As you can see, the code becomes more segmented and readable, but it can actually be written shorter:

  1. Collections.sort(names, (String a, String b) -> b.compareTo(a));  

For functions with only one line of code, you can remove braces {} and return keywords, but you can also write shorter:
  1. Collections.sort(names, (a, b) -> b.compareTo(a));  
The Java compiler can automatically derive parameter types, so you don't have to write the type again. Next let's look at what more convenient lambda expressions can make:

3. Functional Interface

How are Lambda expressions represented in java's type system? Each lambda expression corresponds to a type, usually an interface type. The term "functional interface" refers to an interface that contains only one abstract method, and each lambda expression of that type is matched to that abstract method. Because default methods are not abstract methods, you can also add default methods to your functional interfaces.

We can treat lambda expressions as any interface type that contains only one abstract method to ensure that your interface meets this requirement. You just need to add @Functional Interface annotation to your interface. The compiler will make a mistake if it finds that you annotate more than one abstract method.

  1. @FunctionalInterface  
  2. interface Converter<F, T> {  
  3.     T convert(F from);  
  4. }  
  5. Converter<String, Integer> converter = (from) -> Integer.valueOf(from);  
  6. Integer converted = converter.convert("123");  
  7. System.out.println(converted);    // 123  
Note that if @FunctionalInterface is not specified, the above code is also correct.

Translator's note maps lambda expressions to a single-method interface, which was implemented in other languages before Java 8, such as Rhino JavaScript interpreter. If a function parameter receives a single-method interface and you pass a function, the Rhino interpreter will automatically make a single-interface instance to the function adapter. A typical application scenario is org. The second parameter of addEventListener of. W3C. dom. events. EventTarget is EventListener.

4. Method and Constructor Reference

The code in the previous section can also be represented by static method references:

  1. Converter<String, Integer> converter = Integer::valueOf;  
  2. Integer converted = converter.convert("123");  
  3. System.out.println(converted);   // 123  

Java 8 allows you to use: keywords to pass method or constructor references. The above code shows how to refer to a static method. We can also refer to an object's method:

  1.  converter = something::startsWith;  
  2. String converted = converter.convert("Java");  
  3. System.out.println(converted);    // "J"  
Next, let's look at how constructors are used: keywords are referenced. First, we define a simple class that contains multiple constructors.
  1. class Person {  
  2.     String firstName;  
  3.     String lastName;    
  4.      Person() {}   
  5.      Person(String firstName, String lastName) {  
  6.         this.firstName = firstName;  
  7.         this.lastName = lastName;  
  8.     }  
  9. }   
Next we specify an object factory interface for creating Person objects:
  1. interface PersonFactory<P extends Person> {  
  2.     P create(String firstName, String lastName);  
  3. }  
Here we use constructor references to associate them instead of implementing a complete factory:
  1. PersonFactory<Person> personFactory = Person::new;  
  2. Person person = personFactory.create("Peter""Parker");  
We just need to use Person::new to get a reference to the Person class constructor, and the Java compiler automatically selects the appropriate constructor based on the signature of the PersonFactory.create method.

V. Lambda Scope
In lambda expressions, access to outer scopes is similar to that in older versions of anonymous objects. You can directly access external local variables marked final, or fields of instances, as well as static variables.

6. Accessing Local Variables

We can access the outer local variables directly in lambda expressions:

  1. final int num = 1;  
  2. Converter<Integer, String> stringConverter =(from) -> String.valueOf(from + num);    
  3.  stringConverter.convert(2);     // 3   
But unlike anonymous objects, the variable num here does not need to be declared final, and the code is equally correct:

  1. int num = 1;  
  2. Converter<Integer, String> stringConverter = (from) -> String.valueOf(from + num);    
  3.  stringConverter.convert(2);     // 3   
However, num here must not be modified by subsequent code (that is, implicit final semantics), such as the following can not be compiled:

  1. int num = 1;  
  2. Converter<Integer, String> stringConverter =  
  3.         (from) -> String.valueOf(from + num);  
  4. num = 3;  

It is also not allowed to attempt to modify num in lambda expressions.
Access Object Fields and Static Variables
Unlike local variables, lambda's internal fields for instances and static variables are readable and writable. This behavior is consistent with anonymous objects:

  1. class Lambda4 {  
  2.     static int outerStaticNum;  
  3.     int outerNum;    
  4.      void testScopes() {  
  5.         Converter<Integer, String> stringConverter1 = (from) -> {  
  6.             outerNum = 23;  
  7.             return String.valueOf(from);  
  8.         };   
  9.          Converter<Integer, String> stringConverter2 = (from) -> {  
  10.             outerStaticNum = 72;  
  11.             return String.valueOf(from);  
  12.         };  
  13.     }  
  14. }   
8. Default Method of Access Interface
Remember the Formula example in the first section, which defines a default method sqrt that can be accessed directly by an instance of Formula, including anonymous objects, but not in lambda expressions.
The default method cannot be accessed in the Lambda expression. The following code will not compile:

  1. Formula formula = (a) -> sqrt( a * 100);  
  2. Built-in Functional Interfaces  
The JDK 1.8 API contains many built-in functional interfaces, such as Comparator or or Runnable interfaces, which are commonly used in old Java. These interfaces are annotated with @Functional Interface to be used on lambda.
The Java 8 API also provides many new functional interfaces to make work easier. Some of them come from the Google Guava library. Even if you are familiar with these, it is necessary to see how they are extended to lambda.

Predicate interface

The Predicate interface has only one parameter and returns the boolean type. The interface contains a variety of default methods to combine Predicate into other complex logic (e.g., AND, OR, NON):

  1. Predicate<String> predicate = (s) -> s.length() > 0;    
  2.  predicate.test("foo");              // true  
  3. predicate.negate().test("foo");     // false   
  4.  Predicate<Boolean> nonNull = Objects::nonNull;  
  5. Predicate<Boolean> isNull = Objects::isNull;   
  6.  Predicate<String> isEmpty = String::isEmpty;  
  7. Predicate<String> isNotEmpty = isEmpty.negate();   
Function interface
The Function interface has a parameter and returns a result with some default methods that can be combined with other functions (compose, and then):

  1. Function<String, Integer> toInteger = Integer::valueOf;  
  2. Function<String, String> backToString = toInteger.andThen(String::valueOf);    
  3.  backToString.apply("123");     // "123"   
Supplier interface
The Supplier interface returns the value of an arbitrary paradigm, unlike the Function interface, which has no parameters.

  1. Supplier<Person> personSupplier = Person::new;  
  2. personSupplier.get();   // new Person  
Consumer interface
The Consumer interface represents an operation performed on a single parameter.

  1. Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName);  
  2. greeter.accept(new Person("Luke""Skywalker"));  
Comparator interface

Comparator is a classic interface in old Java, on which Java 8 adds a variety of default methods:

  1. Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName);    
  2.  Person p1 = new Person("John""Doe");  
  3. Person p2 = new Person("Alice""Wonderland");   
  4.  comparator.compare(p1, p2);             // > 0  
  5. comparator.reversed().compare(p1, p2);  // < 0   
Optional interface

Optional is not a function but an interface. It's an auxiliary type to prevent NullPointerException exceptions. This is an important concept to be used in the next session. Now let's take a brief look at what this interface can do:

Optional is defined as a simple container whose value may or may not be null. Before Java 8, a function should return a non-empty object, but occasionally it might return null. In Java 8, you are not recommended to return null but to return Optional.

  1. Optional<String> optional = Optional.of("bam");    
  2.  optional.isPresent();           // true  
  3. optional.get();                 // "bam"  
  4. optional.orElse("fallback");    // "bam"   
  5.  optional.ifPresent((s) -> System.out.println(s.charAt(0)));     // "b"   
Stream interface

java.util.Stream denotes the sequence of operations that can be applied to the last execution of a set of elements. Stream operations are divided into intermediate operations or final operations. The final operation returns a particular type of calculation result, while the intermediate operation returns Stream itself, so that you can string multiple operations in turn. Stream creation requires specifying a data source, such as a subclass of java.util.Collection, List or Set, which Map does not support. Stream operations can be executed serially or in parallel.

First, look at how Stream is used. First, create the data List used by the instance code.

  1. List<String> stringCollection = new ArrayList<>();  
  2. stringCollection.add("ddd2");  
  3. stringCollection.add("aaa2");  
  4. stringCollection.add("bbb1");  
  5. stringCollection.add("aaa1");  
  6. stringCollection.add("bbb3");  
  7. stringCollection.add("ccc");  
  8. stringCollection.add("bbb2");  
  9. stringCollection.add("ddd1");  
Java 8 extends the collection class to create a Stream through Collection.stream() or Collection.parallelStream(). The following sections explain in detail the commonly used Stream operations:

Filter filtering
Filtering uses a predicate interface to filter and retain only qualified elements, which is an intermediate operation, so we can apply other Stream operations (such as forEach) to the filtered results. ForEach needs a function to execute filtered elements in turn. ForEach is a final operation, so we can't perform other Stream operations after forEach.

  1. stringCollection  
  2.     .stream()  
  3.     .filter((s) -> s.startsWith("a"))  
  4.     .forEach(System.out::println);    
  5.  // "aaa2", "aaa1"   
Sort sort
Sorting is an intermediate operation that returns a sorted Stream. If you do not specify a custom Comparator, the default sort is used.

  1. stringCollection  
  2.     .stream()  
  3.     .sorted()  
  4.     .filter((s) -> s.startsWith("a"))  
  5.     .forEach(System.out::println);    
  6.  // "aaa1", "aaa2"   
It should be noted that sorting only creates a well-arranged Stream without affecting the original data source. After sorting, the original data string Collection will not be modified.

  1. System.out.println(stringCollection);  
  2. // ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1  
Map mapping
Intermediate operation map converts elements to other objects in turn according to the specified Function interface. The following example shows converting strings to uppercase strings. You can also use map to translate objects into other types, and the Stream type returned by map is determined by the return value of the function that your map passes in.

  1. stringCollection  
  2.     .stream()  
  3.     .map(String::toUpperCase)  
  4.     .sorted((a, b) -> b.compareTo(a))  
  5.     .forEach(System.out::println);    
  6.  // "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"   
Match Matching
Stream provides a variety of matching operations that allow you to detect whether the specified Predicate matches the entire Stream. All matching operations are final operations and return a boolean type value.
  1. boolean anyStartsWithA =   
  2.     stringCollection  
  3.         .stream()  
  4.         .anyMatch((s) -> s.startsWith("a"));    
  5.  System.out.println(anyStartsWithA);      // true   
  6.  boolean allStartsWithA =   
  7.     stringCollection  
  8.         .stream()  
  9.         .allMatch((s) -> s.startsWith("a"));   
  10.  System.out.println(allStartsWithA);      // false   
  11.  boolean noneStartsWithZ =   
  12.     stringCollection  
  13.         .stream()  
  14.         .noneMatch((s) -> s.startsWith("z"));   
  15.  System.out.println(noneStartsWithZ);      // true   

Count count

Counting is a final operation that returns the number of elements in Stream and the return value type is long.

  1. long startsWithB =   
  2.     stringCollection  
  3.         .stream()  
  4.         .filter((s) -> s.startsWith("b"))  
  5.         .count();    
  6.  System.out.println(startsWithB);    // 3   
Reduce Protocol
This is a final operation that allows multiple elements in a stream to be specified as one element through a specified function. The result of the override is represented by an Optional interface:

  1. Optional<String> reduced =  
  2.     stringCollection  
  3.         .stream()  
  4.         .sorted()  
  5.         .reduce((s1, s2) -> s1 + "#" + s2);    
  6.  reduced.ifPresent(System.out::println);  
  7. // "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"   
Parallel Streams

As mentioned earlier, Stream has two types: serial and parallel. The operations on serial Stream are performed in one thread in turn, while parallel Stream is executed on multiple threads at the same time.

The following example shows how to improve performance through parallel Stream:

First, we create a large table without duplicate elements:

  1. int max = 1000000;  
  2. List<String> values = new ArrayList<>(max);  
  3. for (int i = 0; i < max; i++) {  
  4.     UUID uuid = UUID.randomUUID();  
  5.     values.add(uuid.toString());  
  6. }  
Then we calculate how long it takes to sort the Stream.

Serial sorting:

  1. long t0 = System.nanoTime();    
  2.  long count = values.stream().sorted().count();  
  3. System.out.println(count);   
  4.  long t1 = System.nanoTime();   
  5.  long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);  
  6. System.out.println(String.format("sequential sort took: %d ms", millis));   
// Serial time consumption: 899 ms
Parallel sorting:

  1. long t0 = System.nanoTime();    
  2.  long count = values.parallelStream().sorted().count();  
  3. System.out.println(count);   
  4.  long t1 = System.nanoTime();   
  5.  long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);  
  6. System.out.println(String.format("parallel sort took: %d ms", millis));   
// Parallel sorting time: 472 ms
The above two codes are almost the same, but the parallel version is 50% faster. The only change that needs to be made is to change stream() to parallelStream().
Map
As mentioned earlier, the Map type does not support stream, but Map provides some new and useful ways to handle some everyday tasks.
  1. Map<Integer, String> map = new HashMap<>();    
  2.  for (int i = 0; i < 10; i++) {  
  3.     map.putIfAbsent(i, "val" + i);  
  4. }   

map.forEach((id, val) -> System.out.println(val));
The above code is easy to understand, putIfAbsent does not require additional existence checks, while forEach receives a Consumer interface to operate on each key pair in the map.

The following example shows other useful functions on map:

  1. map.computeIfPresent(3, (num, val) -> val + num);  
  2. map.get(3);             // val33    
  3.  map.computeIfPresent(9, (num, val) -> null);  
  4. map.containsKey(9);     // false   
  5.  map.computeIfAbsent(23, num -> "val" + num);  
  6. map.containsKey(23);    // true   
  7.  map.computeIfAbsent(3, num -> "bam");  
  8. map.get(3);             // val33   

Next, we show how to delete an item in the Map that all keys match:
  1. map.remove(3"val3");  
  2. map.get(3);             // val33    
  3.  map.remove(3"val33");  
  4. map.get(3);             // null   
Another useful method:

  1. map.getOrDefault(42"not found");  // not found  
Merging Map elements is also easy:
  1. map.merge(9"val9", (value, newValue) -> value.concat(newValue));  
  2. map.get(9);             // val9    
  3.  map.merge(9"concat", (value, newValue) -> value.concat(newValue));  
  4. map.get(9);             // val9concat   
What Merge does is insert if the key name does not exist, or merge the values corresponding to the original key and re-insert them into the map.
9. Date API
Java 8 includes a whole new set of time and date APIs under package java.time. The new date API is similar to the open source Joda-Time library, but not exactly the same. The following examples show some of the most important parts of the new API set:

Clock clock

The Clock class provides access to the current date and time. Clock is time zone sensitive and can be used instead of System.currentTimeMillis() to get the current microseconds. Instant classes can also be used to create old java.util.Date objects.

  1. Clock clock = Clock.systemDefaultZone();  
  2. long millis = clock.millis();    
  3.  Instant instant = clock.instant();  
  4. Date legacyDate = Date.from(instant);   // legacy java.util.Date   

Timezones time zone

In the new API, the time zone is represented by ZoneId. The time zone can be easily obtained by using the static method of of. The time zone defines the time lag to UTS, which is extremely important when converting Instant point objects to local date objects.

  1. System.out.println(ZoneId.getAvailableZoneIds());  
  2. // prints all available timezone ids    
  3.  ZoneId zone1 = ZoneId.of("Europe/Berlin");  
  4. ZoneId zone2 = ZoneId.of("Brazil/East");  
  5. System.out.println(zone1.getRules());  
  6. System.out.println(zone2.getRules());   
  7.  // ZoneRules[currentStandardOffset=+01:00]  
  8. // ZoneRules[currentStandardOffset=-03:00]   

LocalTime Local Time

LocalTime defines a time without time zone information, such as 10 p.m., or 17:30:15 p.m. The following example creates two local times using the time zone created by the previous code. Then the time difference between the two periods is calculated in hours and minutes.

  1. LocalTime now1 = LocalTime.now(zone1);  
  2. LocalTime now2 = LocalTime.now(zone2);    
  3.  System.out.println(now1.isBefore(now2));  // false   
  4.  long hoursBetween = ChronoUnit.HOURS.between(now1, now2);  
  5. long minutesBetween = ChronoUnit.MINUTES.between(now1, now2);   
  6.  System.out.println(hoursBetween);       // -3  
  7. System.out.println(minutesBetween);     // -239   
LocalTime provides a variety of factory methods to simplify object creation, including parsing time strings.
  1. LocalTime late = LocalTime.of(235959);  
  2. System.out.println(late);       // 23:59:59    
  3.  DateTimeFormatter germanFormatter =  
  4.     DateTimeFormatter  
  5.         .ofLocalizedTime(FormatStyle.SHORT)  
  6.         .withLocale(Locale.GERMAN);   
  7.  LocalTime leetTime = LocalTime.parse("13:37", germanFormatter);  
  8. System.out.println(leetTime);   // 13:37   

Local Date Local Date

LocalDate indicates an exact date, such as 2014-03-11. The object value is immutable and basically identical to LocalTime. The following example shows how to add or subtract days/months/years to Date objects. Also note that these objects are immutable and that the operation always returns a new instance.

  1. LocalDate today = LocalDate.now();  
  2. LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS);  
  3. LocalDate yesterday = tomorrow.minusDays(2);    
  4.  LocalDate independenceDay = LocalDate.of(2014, Month.JULY, 4);  
  5. DayOfWeek dayOfWeek = independenceDay.getDayOfWeek();   

System.out.println(dayOfWeek);    // FRIDAY
Parsing a LocalDate type from a string is as simple as parsing LocalTime:

  1. DateTimeFormatter germanFormatter =  
  2.     DateTimeFormatter  
  3.         .ofLocalizedDate(FormatStyle.MEDIUM)  
  4.         .withLocale(Locale.GERMAN);    
  5.  LocalDate xmas = LocalDate.parse("24.12.2014", germanFormatter);  
  6. System.out.println(xmas);   // 2014-12-24   
Local DateTime Local Date and Time
Local DateTime represents both time and date, which is equivalent to merging the first two sections into an object. Local DateTime, like Local Time and Local Date, is immutable. Local DateTime provides some ways to access specific fields.

  1. LocalDateTime sylvester = LocalDateTime.of(2014, Month.DECEMBER, 31235959);    
  2.  DayOfWeek dayOfWeek = sylvester.getDayOfWeek();  
  3. System.out.println(dayOfWeek);      // WEDNESDAY   
  4.  Month month = sylvester.getMonth();  
  5. System.out.println(month);          // DECEMBER   
  6.  long minuteOfDay = sylvester.getLong(ChronoField.MINUTE_OF_DAY);  
  7. System.out.println(minuteOfDay);    // 1439   

As long as time zone information is added, it can be converted into a point-in-time Instant object, which can easily be converted into an old-fashioned java.util.Date.

  1. Instant instant = sylvester  
  2.         .atZone(ZoneId.systemDefault())  
  3.         .toInstant();    
  4.  Date legacyDate = Date.from(instant);  
  5. System.out.println(legacyDate);     // Wed Dec 31 23:59:59 CET 2014   

Formatting Local DateTime is the same as formatting time and date. In addition to using predefined formats, we can also define formats ourselves:

  1. DateTimeFormatter formatter =  
  2.     DateTimeFormatter  
  3.         .ofPattern("MMM dd, yyyy - HH:mm");    
  4.  LocalDateTime parsed = LocalDateTime.parse("Nov 03, 2014 - 07:13", formatter);  
  5. String string = formatter.format(parsed);  
  6. System.out.println(string);     // Nov 03, 2014 - 07:13   
Unlike java.text.NumberFormat, the new version of DataTime Formatter is immutable, so it is thread-safe.
Detailed information on time and date format: http://download.java.net/jdk8/docs/api/java/time/format/DateTimeFormatter.html

Annotation Notes

Multiple annotations are supported in Java 8. Let's start with an example to understand what they mean.
First, a wrapper class Hints annotation is defined to place a set of specific Hint annotations:

  1. @interface Hints {  
  2.     Hint[] value();  
  3. }    
  4.  @Repeatable(Hints.class)  
  5. @interface Hint {  
  6.     String value();  
  7. }   
Java 8 allows us to use the same type of annotation many times, just annotate it with @Repeatable. Example 1: Use packaging classes as containers to store multiple annotations (old method)
  1. @Hints({@Hint("hint1"), @Hint("hint2")})  
  2. class Person {}  

Example 2: Using Multiple Annotations (New Method)

  1. @Hint("hint1")  
  2. @Hint("hint2")  
  3. class Person {}  

In the second example, the java compiler implicitly defines the @Hints annotation for you. Understanding this will help you capture this information with reflection:

  1. Hint hint = Person.class.getAnnotation(Hint.class);  
  2. System.out.println(hint);                   // null    
  3.  Hints hints1 = Person.class.getAnnotation(Hints.class);  
  4. System.out.println(hints1.value().length);  // 2   
  5.  Hint[] hints2 = Person.class.getAnnotationsByType(Hint.class);  
  6. System.out.println(hints2.length);          // 2   
Even if we don't define @Hints annotations on Person classes, we can still get @Hints annotations through getAnnotation(Hints.class). A more convenient way is to use getAnnotationsByType to get all @Hint annotations directly.
In addition, Java 8 annotations have been added to two new target s:

  1. @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})  
  2. @interface MyAnnotation {}  
That's all for the new features of Java 8, and there's definitely more to explore. There are many other useful things in JDK 1.8, such as Arrays.parallelSort, StampedLock and Comppletable Future.

Posted by [PQ3]RogeR on Wed, 26 Jun 2019 10:41:14 -0700