In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-22 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article introduces the knowledge of "how to use the new features of Java8". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
New feature of Java language Lambda expression
Lambda expressions (also known as closures) are the most anticipated change at the Java language level throughout the Java 8 distribution, and Lambda allows you to treat a function as an argument to a method (a function is passed into a method as an argument) or code as data: functional programmers are familiar with this concept. Many languages on the JVM platform (Groovy,Scala, … There was Lambda from the beginning, but Java programmers had to replace lambda with anonymous classes that were nothing new
The discussion about Lambda design takes up a lot of time and community efforts. The good news is that a balance is finally found so that Lambdas can be constructed in a new way that is simple and compact. In the simplest form, a lambda can be represented by a comma-separated list of parameters, a-> symbol, and a function body. For example:
Arrays.asList ("a", "b", "d"). ForEach (e-> System.out.println (e))
Note that the type of parameter e is inferred by the compiler. At the same time, you can also give the parameter type directly by including the parameter type and the parameter in parentheses:
Arrays.asList ("a", "b", "d") .forEach ((String e)-> System.out.println (e))
In some cases, the function of lambda will be more complex, so you can put the function body in a pair of curly braces, just like defining a normal function in Java. For example:
Arrays.asList ("a", "b", "d") .forEach (e-> {System.out.print (e); System.out.print (e);})
Lambda can refer to member variables and local variables of a class (if these variables are not final, they will be implicitly converted to final, which is more efficient). For example, the following two code snippets are equivalent:
String separator = ","; Arrays.asList ("a", "b", "d") .forEach ((String e)-> System.out.print (e + separator))
And:
Final String separator = ","; Arrays.asList ("a", "b", "d") .forEach ((String e)-> System.out.print (e + separator))
Lambda may return a value. The type of the return value is also inferred by the compiler. If the function body of lambda has only one line, there is no need to explicitly use the declare statement. The following two code fragments are equivalent:
Arrays.asList ("a", "b", "d") .sort ((E1, e2)-> e1.compareTo (e2))
And:
Arrays.asList ("a", "b", "d") .sort ((E1, e2)-> {int result = e1.compareTo (e2); return result;})
Language designers put a lot of effort into thinking about how to make existing functions friendly to lambda.
The final approach is to add the concept of functional interface. A functional interface is a common interface with a method. Interfaces like this can be implicitly converted to lambda expressions.
Java.lang.Runnable and java.util.concurrent.Callable are the two most typical examples of functional interfaces.
In practical use, functional interfaces are error-prone: if someone adds another method to the interface definition, the interface is no longer functional and the compilation process will fail.
To overcome this vulnerability of functional interfaces and to be able to explicitly declare the intention of interfaces as functional interfaces, Java8 adds a special annotation @ FunctionalInterface (@ FunctionalInterface annotations are added to the existing interfaces of all class libraries in Java8). Let's take a look at the definition of this functional interface:
@ FunctionalInterface public interface Functional {void method ();} one thing to keep in mind is that the default method and the static method do not affect the contract of the functional interface, and can be used at will:
@ FunctionalInterface public interface FunctionalDefaultMethods {void method ()
Default void defaultMethod () {}
} Lambda is the biggest selling point of Java 8. It has the potential to attract more and more programmers to the Java platform and provides an elegant way to support functional programming in a pure Java environment. You can refer to the official documentation for more details.
Let's look at an example:
Public class lambda and functional programming {@ Test public void test1 () {List names = Arrays.asList ("peter", "anna", "mike", "xenia"); Collections.sort (names, new Comparator () {@ Override public int compare (String a, String b) {return b.compareTo (a);}}) System.out.println (Arrays.toString (names.toArray ();} @ Test public void test2 () {List names = Arrays.asList ("peter", "anna", "mike", "xenia"); Collections.sort (names, (String a, String b)-> {return b.compareTo (a);}) Collections.sort (names, (String aquin string b)-> b.compareTo (a)); Collections.sort (names, (a, b)-> b.compareTo (a)); System.out.println (Arrays.toString (names.toArray ();} static void add (double aMagin string b) {System.out.println (a + b) } @ Test public void test5 () {D d = (aMaginb)-> add (arecine b); / / interface D {/ / void get (int iMagneString j) / /} / / it is required here that the two parameters of add match the two parameters of get and the return type must be the same, otherwise error / / static void add (double aline string b) {/ / System.out.println (a + b); / /}} @ FunctionalInterface interface D {void get (int iForce string j);} functional interface
The so-called functional interface is an interface with only one abstract method. Note that this is an abstract method, because the default method is added to the Java8, but the functional interface does not care about whether there is a default method in the interface. Generally, functional interfaces can be annotated in the form of @ FunctionalInterface annotation to indicate that this is a functional interface. Whether the annotation is annotated or not has no actual effect on functional interfaces, but this annotation is generally recommended, just like using @ Override annotation.
How do lambda expressions conform to the Java type system? Each lambda corresponds to a given type and is described by an interface. This interface, called a functional interface (functional interface), must contain only an abstract method declaration. Each lambda expression of that type will be matched to this abstract method. So the default method is not abstract, you are free to add default methods to your functional interface.
We can use any interface as an lambda expression, as long as the interface contains only one abstract method. To ensure that your interface meets the requirements, you need to add the @ FunctionalInterface annotation. The compiler knows this annotation, and once you try to add a second abstract method declaration to the interface, it will throw a compiler error.
Here are a few examples
Public class functional interface uses {@ FunctionalInterface interface A {void say (); default void talk () {}} @ Test public void test1 () {AA = ()-> System.out.println ("hello"); a.say ();} @ FunctionalInterface interface B {void say (String I) } public void test2 () {/ / the following two are equivalent, both refer to a method through the B interface, and the method can directly use:: to reference BB = System.out::println; B b1 = a-> Integer.parseInt ("s") as the method / / the a here can be changed to something else, but if you pass the method to the interface as its method implementation Bb2 = Integer::valueOf;//i and the variable type of the method input parameter is always the same, you can directly replace Bb3 = String::valueOf; / / Bb4 = Integer::parseInt; type, so you cannot use} @ FunctionalInterface interface C {int say (String I). } public void test3 () {C c = Integer::parseInt;// method parameters are the same as those of interface methods and can be replaced. Int I = c.say ("1"); / / when I replace the int of the C interface with void, I get an error because the return type is inconsistent. System.out.println (I); / / to sum up, lambda expressions provide an easy way to pass a method to an interface. / / A functional interface is an interface that only provides an abstract method, which is injected by lambda expressions without writing implementation classes and / / anonymous inner classes, so you can save a lot of code, such as implementing the runnable interface. / / functional programming refers to manipulating a method as a parameter or reference. In addition to ordinary methods, static methods and constructors can also be operated in this way. }}
Keep in mind that if the @ FunctionalInterface annotation is left out, the code still works.
Method reference
Lambda expressions and method references
Once you have a functional interface, you can use Lambda expressions and method references. In fact, the function descriptor in the table of the functional interface is the Lambda expression, and the Lambda expression in the functional interface is equivalent to the effect of an anonymous inner class. Take a simple example:
Public class TestLambda {
Public static void execute (Runnable runnable) {runnable.run ();} public static void main (String [] args) {/ / Java8 before execute (new Runnable () {@ Override public void run () {System.out.println ("run");}}); / / use the Lambda expression execute (()-> System.out.println ("run"));}
}
As you can see, Lambda expressions can use less code but are expressed more clearly than using anonymous inner classes. Note that Lambda expressions are not exactly equivalent to anonymous inner classes, but the difference lies in the pointing of this and the masking of local variables.
Method references can be seen as a more concise expression of Lambda expressions, using the:: operator, there are three main types of method references:
Method references pointing to static methods (such as Integer's parseInt method, writing Integer::parseInt); method references pointing to any type of instance method (such as String's length method, writing String::length); method references pointing to existing object instance methods (for example, suppose you have a local variable localVariable for storing Variable-type objects, which supports instance method getValue, then it can be written as localVariable::getValue).
Take a simple example of a method reference:
Function stringToInteger = (String s)-> Integer.parseInt (s)
/ / use method reference
Function stringToInteger = Integer::parseInt
There is also a special form of method reference, constructor reference, assuming that a class has a default constructor, then the form of method reference is:
Supplier C1 = SomeClass::new;SomeClass S1 = c1.get ()
/ / equivalent to
Supplier C1 = ()-> new SomeClass (); SomeClass S1 = c1.get ()
If it is the case that the constructor has one parameter:
Function C1 = SomeClass::new;SomeClass S1 = c1.apply
/ / equivalent to
Function C1 = I-> new SomeClass (I); SomeClass S1 = c1.apply (100); default method of the interface
Java 8 enables us to use the default keyword to add a non-abstract method implementation to the interface. This feature is also called extension method (Extension Methods). As shown in the following example:
The default method of the public class interface {class B implements A {/ / void a () {} implementation class methods cannot have the same name} interface A {/ / can have multiple default methods public default void a () {System.out.println ("a");} public default void b () {System.out.println ("b") } / / static and default cannot be used at the same time / / public static default void c () {/ / System.out.println ("c"); / /}} public void test () {BB = new B (); b.a ();}}
The reason for the emergence of the default method is for the extension of the original interface, after having the default method, we are not afraid of the code incompatibility caused by changing the original interface to the programs that already use these interfaces. Some default methods have also been added to some interfaces in Java8, such as the Map interface and so on. In general, there are two scenarios that use the default method: optional methods and multiple inheritance of behaviors.
The use of the default method is relatively simple, and the only thing to pay attention to is how to handle the conflict of the default method. You can refer to the following three rules on how to handle conflicts with default methods:
The methods in the class have the highest priority. The method declared in the class or parent class takes precedence over any method declared as the default method.
If you cannot judge according to the first rule, the priority of the subinterface is higher: when the function signature is the same, the interface with the most specific default method is preferred. That is, if B inherits A, then B is more specific than A.
Finally, if it is still impossible to determine, a class that inherits multiple interfaces must explicitly choose which implementation of the default method to use by explicitly overriding and calling the desired method. So how do you explicitly specify:
Public class C implements B, A {public void hello () {B.super () .hello ();}}
Use X.super.m (..) Explicitly call the method you want to call.
Java 8 extends the declaration of an interface with two new concepts: default methods and static methods. The default method makes the interface a bit like Traits (trait in Scala is similar to Interface in Java, but it can contain implementation code, which is a new feature added by Java8 at present), but unlike traditional interfaces, it allows new methods to be added to existing interfaces while maintaining compatibility with old versions of the code.
The default method differs from the abstract method in that the abstract method must require implementation, but the default method does not. Instead, each interface must provide a so-called default implementation so that all interface implementers will inherit it by default (which can be overridden if necessary). Let's look at the following example:
Private interface Defaulable {/ / Interfaces now allow default methods, the implementer may or / / may not implement (override) them. Default String notRequired () {return "Default implementation";} private static class DefaultableImpl implements Defaulable {} private static class OverridableImpl implements Defaulable {@ Override public String notRequired () {return "Overridden implementation";}}
The Defaulable interface declares a default method notRequired () with the keyword default, and DefaultableImpl, one of the implementers of the Defaulable interface, implements the interface and leaves the default method as it is. OverridableImpl, another implementer of the Defaulable interface, overrides the default method with his own method.
Another interesting feature of Java 8 is that interfaces can declare (and provide implementations) static methods. For example:
Private interface DefaulableFactory {/ / Interfaces now allow static methods static Defaulable create (Supplier
< Defaulable >Supplier) {return supplier.get ();}}
The following code snippet glues the above default method to the static method.
Public static void main (String [] args) {Defaulable defaulable = DefaulableFactory.create (DefaultableImpl::new); System.out.println (defaulable.notRequired ()); defaulable = DefaulableFactory.create (OverridableImpl::new); System.out.println (defaulable.notRequired ());}
The console output of this program is as follows:
Default implementation Overridden implementation in JVM, the implementation of the default method is very efficient and provides support for method calls through bytecode instructions. The default method allows you to continue to use the existing Java interface while ensuring a normal compilation process. A good example of this is that a large number of methods are added to the java.util.Collection interface: stream (), parallelStream (), forEach (), removeIf (),...
Although the default method is very powerful, there is one thing we need to be careful about when using the default method: before declaring a default method, think carefully about whether it is really necessary to use the default method, because the default method brings ambiguity to the program and is prone to compilation errors in complex inheritance systems. Please refer to the official documentation for more details.
Repetitive annotation
Since Java 5 introduced the annotation mechanism, this feature has become very popular and widely used. However, one limitation of using annotations is that the same annotations can only be declared once in the same location, not multiple times. Java 8 breaks this rule by introducing repeated annotations so that the same annotations can be declared multiple times in the same place.
The repetitive annotation mechanism itself must be annotated with @ Repeatable. In fact, this is not a change at the language level, but more about the skills of the compiler, and the underlying principles remain the same. Let's look at an example of getting started:
Package com.javacodegeeks.java8.repeatable.annotations; import java.lang.annotation.ElementType;import java.lang.annotation.Repeatable;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target; public class RepeatingAnnotations {@ Target (ElementType.TYPE) @ Retention (RetentionPolicy.RUNTIME) public @ interface Filters {Filter [] value () @ Target (ElementType.TYPE) @ Retention (RetentionPolicy.RUNTIME) @ Repeatable (Filters.class) public @ interface Filter {String value ();} @ Filter ("filter1") @ Filter ("filter2") public interface Filterable {} public static void main (String [] args) {for (Filter filter: Filterable.class.getAnnotationsByType (Filter.class)) {System.out.println (filter.value ());}
As we can see, an annotated class Filter,Filters using @ Repeatable (Filters.class) annotations is just an array of Filter annotations, but the Java compiler does not want programmers to be aware of Filters. In this way, the interface Filterable has two Filter annotations (no mention of Filter).
At the same time, the reflection-related API provides a new function getAnnotationsByType () to return the type of duplicate annotations (note that Filterable.class.getAnnotation (Filters.class) will return an instance of Filters after being processed by the compiler).
The output of the program is as follows:
For more details on filter1 filter2, please refer to the official documentation.
The new feature method parameter name of Java compiler can be obtained by reflection.
For a long time, Java programmers have been inventing different ways to keep the names of method parameters in Java bytecode and to obtain them at run time (for example, the Paranamer class library). Finally, in Java 8, this much-needed functionality is added to the language level (by reflecting the API and Parameter.getName () methods) and bytecode files (through the new version of javac's-parameters option).
Package com.javacodegeeks.java8.parameter.names
Import java.lang.reflect.Method; import java.lang.reflect.Parameter
Public class ParameterNames {public static void main (String [] args) throws Exception {Method method = ParameterNames.class.getMethod ("main", String [] .class); for (final Parameter parameter: method.getParameters ()) {System.out.println ("Parameter:" + parameter.getName ());} if you do not compile the class with the-class parameter, and then run the class, you will get the following output:
Parameter: arg0 if you compile this class with the-parameters parameter, the structure of the program will be different (the real name of the parameter will be displayed):
Parameter: args
New Features of Java Class Library
Java 8 improves support for concurrent programming, functional programming, date / time related operations, and more by adding a large number of new classes and extending the functionality of existing classes.
Optional
By far, the infamous null pointer exception is by far the most common cause of Java application failure. In the past, to solve null pointer exceptions, Google's famous Guava project introduced the Optional class. Guava prevents code contamination by checking null values, which encourages programmers to write cleaner code. Inspired by Google Guava, the Optional class has become part of the Java 8 class library.
Optional is actually a container: it can hold the value of type T, or just null. Optional provides a lot of useful methods so that we don't have to explicitly detect null values. Please refer to the official documentation for more details.
Let's use two small examples to demonstrate how to use the Optional class: one that allows null values and one that does not allow null values.
Public class null pointer Optional {public static void main (String [] args) {/ / use the of method and still report a null pointer exception / / Optional optional = Optional.of (null); / / System.out.println (optional.get ()) / / throw an exception without this element / / Exception in thread "main" java.util.NoSuchElementException: No value present// at java.util.Optional.get (Optional.java:135) / / at com.javase.Java8. Null pointer Optional.main (null pointer Optional.java:14) / / Optional optional1 = Optional.ofNullable (null); / / System.out.println (optional1.get ()); Optional optional = Optional.ofNullable (null); System.out.println (optional.isPresent ()); System.out.println (optional.orElse (0)) / / give the initial value System.out.println when the value is empty (optional.orElseGet (()-> new String [] {"a"})) / / use the callback function to set the default value / / even if the element passed into the Optional container is empty, using the optional.isPresent () method will not report a null pointer exception / / so you can write code to avoid null pointer exceptions by optional.orElse / / output Optional.empty. }}
IsPresent () returns true if the instance of the Optional class is a non-null value, or false from. To prevent Optional from being null, the orElseGet () method produces a default value through a callback function. The map () function converts the value of the current Optional and returns a new Optional instance. The orElse () method is similar to the orElseGet () method, but orElse accepts a default value instead of a callback function. Here is the output of this program:
Full Name is set? False Full Name: [none] Hey Stranger! Let's look at another example:
Optional
< String >FirstName = Optional.of ("Tom"); System.out.println ("First Name is set?" + firstName.isPresent ()); System.out.println ("First Name:" + firstName.orElseGet (()-> "[none]")); System.out.println (firstName.map (s-> "Hey" + s + "!"). OrElse ("Hey Stranger!"); System.out.println ()
Here is the output of the program:
First Name is set? True First Name: Tom Hey Tom!
Stream
The newly added Stream API (java.util.stream) introduces the true functional programming style to Java. This is by far the best complement to the Java class library, because Stream API can greatly provide Java programmers with productivity, allowing programmers to write efficient, clean, and concise code.
Stream API greatly simplifies the processing of the collection framework (but its scope is not limited to the processing of the collection framework, as we will see later). Let's take a simple task class as an example:
The Task class has a concept of fraction (or pseudo-complexity), followed by a state where the value can be OPEN or CLOSED. Let's introduce a small collection of Task as a demonstration example:
Final Collection
< Task >Tasks = Arrays.asList (new Task (Status.OPEN, 5), new Task (Status.OPEN, 13), new Task (Status.CLOSED, 8))
The first question we're going to discuss next is what are the total scores for all tasks with a status of OPEN? Prior to Java 8, the general solution was to use foreach loops, but in Java 8 we could use stream: a string of elements that support continuous, parallel aggregation operations.
/ / Calculate total points of all active tasks using sum () final long totalPointsOfOpenTasks = tasks .stream () .filter (task-> task.getStatus () = = Status.OPEN) .mapToInt (Task::getPoints) .sum (); System.out.println ("Total points:" + totalPointsOfOpenTasks)
The output of the program on the console is as follows:
Total points: 18
Here are a few notes.
First, the task collection is transformed into its corresponding stream representation. The filter operation then filters out the task with a status of CLOSED.
Next, the mapToInt operation calls the getPoints method of each task instance through Task::getPoints to convert the stream of Task into the stream of Integer. Finally, all the scores are added up with the sum function to get the final result.
Before continuing with the following example, there are a few things to note about stream (details are here). Stream operations are divided into intermediate operations and final operations.
The intermediate operation returns a new stream object. Intermediate operations are always evaluated lazily, and running an intermediate operation like filter does not actually do any filtering. Instead, it traverses the element to produce a new stream object that contains all the elements in the original stream that match the given predicate.
Final operations such as forEach and sum may traverse the stream directly, producing a result or side effect. When the final operation is completed, the stream pipeline is considered to have been consumed and can no longer be used. In most cases, the final operation is to use early evaluation to complete the traversal of the underlying data source as soon as possible.
Another valuable aspect of stream is its native support for parallel processing. Let's take a look at this example of the sum of task scores.
Another valuable aspect of stream is its native support for parallel processing. Let's take a look at this example of the sum of task scores.
/ / Calculate total points of all tasksfinal double totalPoints = tasks .stream () .parallel () .map (task-> task.getPoints ()) / / or map (Task::getPoints) .reduce (0, Integer::sum); System.out.println ("Total points (all tasks):" + totalPoints)
This example is similar to the first example, but the difference is that the program runs in parallel, and then the reduce method is used to calculate the final result. Here is the output of this example on the console:
Total points (all tasks): 26.0 often has this requirement: we need to group the elements in the collection according to some criteria. Stream can also handle such requirements. Here is an example:
/ / Group tasks by their statusfinal Map
< Status, List< Task >> map = tasks .stream () .upload (Collectors.groupingBy (Task::getStatus)); System.out.println (map)
The console output of this example is as follows:
{CLOSED= [[CLOSED, 8]], OPEN= [[OPEN, 5], [OPEN, 13]]} Let's calculate the average of each task score (or weight) in the entire set to end the task example.
/ / Calculate the weight of each tasks (as percent of total points) final Collection
< String >Result = tasks .stream () / / Stream
< String >.mapToInt (Task::getPoints) / / IntStream .asLongStream () / / LongStream .mapToDouble (points-> points / totalPoints) / / DoubleStream .boxed () / / Stream
< Double >.mapToLong (weigth-> (long) (weigth * 100)) / / LongStream .mapToObj (percentage-> percentage + "%") / / Stream
< String>.coach (Collectors.toList ()); / / List
< String >System.out.println (result)
Here is the console output of this example:
[19%, 50%, 30%] finally, as mentioned earlier, Stream API does not just deal with the Java collection framework. Typical Istroke O operations, such as reading data line by line from a text file, are also suitable for Stream API processing. Here is an example to prove this.
Final Path path = new File (filename). ToPath (); try (Stream
< String >Lines = Files.lines (path, StandardCharsets.UTF_8)) {lines.onClose (()-> System.out.println ("Done!")) .forEach (System.out::println);}
Calling the onClose method on a stream object returns a stream object with a new shutdown function based on the original functionality, and when the close () method is called on the stream object, the handler associated with the shutdown executes.
Stream API, Lambda expressions and method references, in conjunction with interface default methods and static methods, are Java 8's responses to modern software development paradigms. Please refer to the official documentation for more details.
Date/Time API (JSR 310)
Java 8 further strengthens its handling of dates and times by releasing a new Date-Time API (JSR 310). Manipulating dates and times has always been one of the most painful things for Java programmers. Standard java.util.Date and later java.util.Calendar have not improved this situation at all (it can be said that they are somewhat more complex).
This situation directly led to the birth of Joda-Time--, a very powerful Java API that can replace standard date / time processing. Java 8's new Date-Time API (JSR 310) is largely influenced by Joda-Time and absorbs its essence. The new java.time package covers all operations dealing with date, time, date / time, time zone, time (instants), process (during) and clock (clock). When designing the new version of API, pay great attention to compatibility with the old version of API: no changes are allowed (lessons learned from java.util.Calendar). If you need to modify it, a new instance of this class will be returned.
Let's take a look at the usage of the main classes in the new version of API with examples. The first is the Clock class, which can get the current time, date and time by specifying a time zone. Clock can replace System.currentTimeMillis () and TimeZone.getDefault ().
/ / Get the system clock as UTC offset final Clock clock = Clock.systemUTC (); System.out.println (clock.instant ()); System.out.println (clock.millis ())
Here is the output of the program on the console:
2014-04-12T15:19:29.282Z 1397315969360
The other classes we need to focus on are LocaleDate and LocalTime. LocaleDate only holds the date portion in ISO-8601 format and has no time zone information. Accordingly, LocaleTime holds only the time portion of the ISO-8601 format and no time zone information. Both LocaleDate and LocalTime are available from Clock.
/ / Get the local date and local timefinal LocalDate date = LocalDate.now (); final LocalDate dateFromClock = LocalDate.now (clock); System.out.println (date); System.out.println (dateFromClock); / / Get the local date and local timefinal LocalTime time = LocalTime.now (); final LocalTime timeFromClock = LocalTime.now (clock); System.out.println (time); System.out.println (timeFromClock)
Here is the output of the program on the console:
2014-04-12 2014-04-12 11 1414 54.568 1515 548 54.568
Here is the output of the program on the console:
2014-04-12T11:47:01.017-04:00 [America/New_York] 2014-04-12T15:47:01.017Z 2014-04-12T08:47:01.017-07:00 [America/Los_Angeles] finally, let's take a look at the Duration class: a period of time in seconds and nanoseconds. Duration makes it easy to calculate the differences between two days. Let's look at an example of this.
/ / Get duration between two datesfinal LocalDateTime from = LocalDateTime.of (2014, Month.APRIL, 16, 0, 0, 0); final LocalDateTime to = LocalDateTime.of (2015, Month.APRIL, 16, 23, 59, 59); final Duration duration = Duration.between (from, to); System.out.println ("Duration in days:" + duration.toDays ()); System.out.println ("Duration in hours:" + duration.toHours ())
The above example calculates the process between April 16, 2014 and April 16, 2014. Here is the output of the program on the console:
Duration in days: 365 Duration in hours: 8783 the overall impression of Java 8's improvements in date / time API is very, very good. This is partly because it is based on the Joda-Time of "fighting for a long time", and partly because it takes a lot of time to design it, and this time the programmer's voice is recognized. Please refer to the official documentation for more details.
Parallel (parallel) array
Java 8 adds a large number of new methods for parallel processing of arrays. It can be said that the most important is the parallelSort () method, because it can greatly improve the speed of array sorting on multicore machines. The following example shows the use of the new method (parallelXxx).
Package com.javacodegeeks.java8.parallel.arrays; import java.util.Arrays;import java.util.concurrent.ThreadLocalRandom; public class ParallelArrays {public static void main (String [] args) {long [] arrayOfLong = new long [20000]; Arrays.parallelSetAll (arrayOfLong, index-> ThreadLocalRandom.current () .nextInt (1000000)) Arrays.stream (arrayOfLong). Limit (10). ForEach (I-> System.out.print (I + ")); System.out.println (); Arrays.parallelSort (arrayOfLong); Arrays.stream (arrayOfLong). Limit (10). ForEach (I-> System.out.print (I +")); System.out.println ();}}
The above code snippet uses the parallelSetAll () method to randomly assign an array of 20000 elements. Then, call the parallelSort method. This program first prints out the values of the first 10 elements, and then sorts the entire array. The output of this program on the console is as follows (note that the array elements are randomly produced):
Unsorted: 591217 891976 443951 424479 766825 351964 242997 642839 119108 552378 Sorted: 39 220 263 268 325 607 655 678 723 793
CompletableFuture
Before Java8, we will use the Future interface provided by JDK to perform some asynchronous operations. In fact, CompletableFuture also implements the Future interface and executes tasks based on ForkJoinPool, so in essence, CompletableFuture is just an encapsulation of the original API. The difference between using CompletableFuture and the original Future is that you can combine two Future, or if the two Future are dependent. You can wait until the first one has been executed before implementing the second feature.
Let's take a look at the basic ways to use it:
Public Future getPriceAsync (final String product) {final CompletableFuture futurePrice = new CompletableFuture (); new Thread (()-> {double price = calculatePrice (product); futurePrice.complete (price); / / use the complete method to set the return value of future}) .start (); return futurePrice;}
Once you have the Future, you can use the get method to get the results. CompletableFuture provides some factory methods to simplify these API and uses these API in a functional programming way, such as:
Fufure price = CompletableFuture.supplyAsync (()-> calculatePrice (product))
Is the code much simpler all of a sudden? As mentioned earlier, CompletableFuture can combine multiple Future, whether there is a dependency between Future or no dependency.
If the second request depends on the result of the first request, you can use the thenCompose method to combine the two Future
Public List findPriceAsync (String product) {List priceFutures = tasks.stream () .map (task-> CompletableFuture.supplyAsync (()-> task.getPrice (product), executor)) .map (future-> future.thenApply (Work::parse)) .map (future-> future.thenCompose (work-> CompletableFuture.supplyAsync (()-> Count.applyCount (work), executor)) .map (Collectors.toList ()) Return priceFutures.stream () .map (CompletableFuture::join) .requests (Collectors.toList ());}
The above code uses thenCompose to combine two CompletableFuture. The second parameter of the supplyAsync method accepts a custom Executor. First, use CompletableFuture to execute a task, call the getPrice method to get a Future, then use the thenApply method to apply the result of Future to the parse method, then use the result after parse as a parameter to execute an applyCount method, then collect it into a CompletableFuture List, and finally use a stream to call the join method of CompletableFuture, which is to wait for all asynchronous tasks to finish execution and get the final result.
Note that two streams must be used here, and if the join method is called in one stream, all operations will be performed serially, not asynchronously, because of the delay nature of Stream.
Let's look at an example where there is no dependency between two Future:
Future futurePriceInUsd = CompletableFuture.supplyAsync (()-> shop.getPrice ("price1")) .thenCombine (CompletableFuture.supplyAsync (()-> shop.getPrice ("price2")), (S1, S2)-> S1 + S2)
There are two asynchronous tasks, and the second parameter of using the thenCombine method to combine the two Future,thenCombine methods is the operation function used to merge the return values of the two Future methods.
Sometimes we don't have to wait for all the asynchronous tasks to finish, just one of them, and CompletableFuture provides this method:
/ / suppose the getStream method returns a StreamCompletableFuture [] futures = getStream ("listen") .map (f-> f.thenAccept (System.out::println)) .toArray (CompletableFuture []:: new); / / wait for one of them to finish executing CompletableFuture.anyOf (futures). Join (); use the anyOf method to respond to the completion event of CompletableFuture. New Features of Java Virtual Machine (JVM)
The PermGen space has been removed and replaced by Metaspace (JEP 122). The JVM options-XX:PermSize and-XX:MaxPermSize are replaced by-XX:MetaSpaceSize and-XX:MaxMetaspaceSize, respectively.
That's all for "how to use the new features of Java8". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.