1

Java8 Advantages: Faster speed, less code (new syntax Lambda expression added), powerful Stream API, easy to parallelize, minimize null pointer exception Optional;

1. Lambda expression

Lambda is an anonymous function, we can understand a Lambda expression as a piece of code that can be passed (pass the code like data). Can replace most of the anonymous inner classes, can write more concise and flexible code. Especially in the traversal of collections and other collection operations, the code structure can be greatly optimized. As a more compact code style, Java's language expressiveness has been improved. JDK also provides a large number of built-in functional interfaces for us to use, making the use of Lambda expressions more convenient and efficient.
[1] from anonymous class to Lambda: Although some interfaces can be easily implemented using Lambda expressions, not all interfaces can be implemented using Lambda expressions. Lambda specifies that there can only be one method that needs to be implemented in an interface, not that there can only be one method in an interface.

There is another new feature in jdk8: default, the method modified by default will have a default implementation, which is not a method that must be implemented, so it does not affect the use of Lambda expressions. There will be special introductions later.

//匿名类
Runnable runnable1 = new Runnable() {
    @Override
    public void run() {
        System.out.printf("Hello World!");
    }
};
/**
 *1.简化参数类型,可以不写参数类型,但是必须所有参数都不写
 *2.简化参数小括号,如果只有一个参数则可以省略参数小括号
 *3.简化方法体大括号,如果方法条只有一条语句,则可以胜率方法体大括号(如下案例)
 *4.如果方法体只有一条语句,并且是 return 语句,则可以省略方法体大括号和rerun关键字:X x= a -> a+3;
 *Lambda 表达式展示:
 */
Runnable runnable2 = ()-> System.out.printf("Lambda 表达式");

[2] originally used an anonymous inner class as a parameter to pass to the Lambda expression :

//原来使用匿名内部类作为参数传递
TreeSet ts = new TreeSet<>(new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return Integer.compare(o1.length(),o2.length());
    }
});
//Lambda 表达式作为参数传递
TreeSet<String> ts2 = new TreeSet<>((o1,o2)-> Integer.compare(o1.length(),o2.length()));

[3] Lambda Expression Syntax : Lambda expressions introduce a new syntax element and operator in the Java language. This operator is "->", which is called the Lambda operator or the head trimming operator. It divides the Lambda into two parts:

■ Left: All parameters required by the lambda expression are specified;
■ Right: specifies the Lambda body, that is, the function to be executed by the Lambda expression;

[ syntax format- ] : no parameters, no return value, and the Lambda body only needs one statement;

Runnable runnable2 = ()-> System.out.printf("Lambda 表达式"); 

[ syntax format two ] : Lambda requires a parameter;

Consumer<String> fun = (args) -> System.out.printf(args);

[ syntax format three ] : Lambda only needs one parameter, the parentheses of the parameter can be omitted;

Consumer<String> fun = args -> System.out.printf(args);

[ syntax format four ] : Lambda requires two parameters and has a return value;

BinaryOperator<Long> bo = (x,y)->{    System.out.printf("实现函数接口方法");    return x+y;};

[ syntax format five ] : When there is only one statement in the Lambda body, return and braces can be omitted;

BinaryOperator<Long> bo = (x,y) -> x+y;

[ syntax format six ] : data type can be omitted, because it can be inferred by the compiler, called "type inference": the parameter type is inferred according to the context;

BinaryOperator<Long> bo = (Long x,Long y)->{    
    System.out.printf("实现函数接口方法");    
    return x+y;
};

[4] traverse the collection: can call the forEach(Consumer<? super E> action) method of the collection to traverse the elements in the collection by means of lambda expressions. The Consumer interface is a functional interface provided by jdk for us.

ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1,2,3,4,5);
//lambda表达式 方法引用
list.forEach(System.out::println);
list.forEach(element -> {
    if (element % 2 == 0) {
      System.out.println(element);
    }
});

[5] delete a set: delete an element in the set through the removeIf(Predicate<? super E> filter) method. Predicate is also a functional interface provided by jdk, which can simplify the writing of the program.

ArrayList<Item> items = new ArrayList<>();
Collections.addAll(list, 1,2,3,4,5);
items.removeIf(ele -> ele.getId() == 3);

[6] Sorting of elements in the set: To sort the elements in the set, you must call the sort method and pass in the anonymous inner class of the comparator to rewrite the compare method. We can now use lambda expressions to simplify the code.

ArrayList<Item> list= new ArrayList<>();
Collections.addAll(list, 6,27,7,4,2);
list.sort((o1,o2) -> o1.getId() - o2.getId());

2. Functional interface


[1] An interface that contains only one abstract method is called a functional interface;
[2] You can create objects of this interface through Lambda expressions. (If the lambda expression throws a checked exception, the exception needs to be declared on the abstract method of the target interface).
[3] We can use the @FunctionalInterface annotation on any functional interface to check whether it is a functional interface, indicating that the interface is a functional interface.

@FunctionalInterface
public interface MyLambda<T> {
    public T getValue(T t);
}
public String toUpperString(MyLambda<String> mf, String str){
    return mf.getValue(str);
}
//为了将 Lambda 表达式作为参数传递,接收 Lambda 表达式的参数类型必须是与 Lambda 表达式兼容的函数式接口的类型
String newStr = toUpperString((str)-> str.toUpperCase(),"abcde");

[4] Java has four built-in core functional interfaces :

functional interfaceParameter Typereturn typeuse
Consumer<T> consumer interfaceTvoidApply an operation to an object of type T, including the method: void accept(T t);
Supplier<T> supply interfacenoneTThe return type is T object, including the method: T get();
Function<T, R> functional interfaceTRApplies an operation to an object of type T and returns the result. The result is an object of type R. Include method: R apply(T t)
Predicate<T> Predicate interfaceTbooleanDetermines whether an object of type T satisfies a constraint and returns a Boolean value, including the method Boolean test(T t)
public class Java8Tester {
   public static void main(String args[]){
      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
      // Predicate<Integer> predicate1 = n -> n%2 == 0
      // n 是一个参数传递到 Predicate 接口的 test 方法
      // 如果 n%2 为 0 test 方法返回 true
      System.out.println("输出所有偶数:");
      eval(list, n-> n%2 == 0 );
   }
   public static void eval(List<Integer> list, Predicate<Integer> predicate) {
      for(Integer n: list) {
         if(predicate.test(n)) {
            System.out.println(n + " ");
         }
      }
   }
}

3. Method reference and constructor reference


[1] method reference : When the operation to be passed to the Lambda body, there is already a method implemented, you can use the method reference! (The parameter list for implementing an abstract method must match the parameter list of the method in the method reference!) Method reference: Use the operator " ::**" to separate the method name from the object or class name. The following three main use cases: When using method reference, it is necessary to ensure that the parameter list and return value type of the reference method are consistent with the parameter list and return value type of the functional interface method we are currently implementing.
①, object :: instance method; ②, class :: static method; ③, class :: instance method**;

(x) -> System.out.println(x);
//等同于
System.out::println
BinaryOperator<Double> bo = (x,y) -> Math.pow(x,y);
//等同于
BinaryOperator<Double> bo = Math::pow;
compare((x,y) -> x.equals(y),"abcd","abcd");
//等同于
compare(String::equals,"abc","abc");(x) -> System.out.println(x);//等同于System.out::printlnBinaryOperator<Double> bo = (x,y) -> Math.pow(x,y);//等同于BinaryOperator<Double> bo = Math::pow;compare((x,y) -> x.equals(y),"abcd","abcd");//等同于compare(String::equals,"abc","abc");

Note: When the first parameter of the method that needs to be referenced is the calling object, and the second parameter is the second parameter (or no parameter) of the method that needs to be referenced:

ClassName::methodName

[2] Constructor reference: Format: ClassName :: new Combined with the functional interface, it is automatically compatible with the methods in the functional interface. The constructor reference can be assigned to the defined method, and the parameter list of the constructor should be consistent with the parameter list of the abstract method in the interface! Which constructor is called depends on the definition of the method parameters in the functional interface. We create objects in two ways (without parameters and with parameters), as follows:

//【案例一】无参构造器创建对象  使用Employee的无参构造器.
//使用 Supplier函数接口  因为 Supplier接口的抽象方法没有入参 可以参考二中的函数式编程.
Supplier<Employee> sup = Employee::new;
//【案例二】有参构造器创建对象  使用Employee的有参构造器.
//使用 Function函数接口  因为 Function接口的抽象方法有入参 可以参考二中的函数式编程.
Function<Integer,Employee> fun = (n) -> new MyClass(n);
//构造器应用改造后:
Function<Integer,Employee> fun = MyClass::new;

[3] array reference: same as the constructor reference, the format is type[] :: new

Function<Integer,Integer[]> fun = (n) -> new Integer[n];
Function<Integer,Integer[]> fun = Integer[]::new;

4. Stream API


There are two of the most important changes in Java 8. The first is a Lambda expression; the other is the Stream API ( java.util.stream. ). Stream is a key abstraction for working with collections in Java 8. It can specify the operations you want to perform on collections, and can perform very complex operations such as finding, filtering, and mapping data. Using the Stream API to operate on collection data is similar to performing database queries using SQL. You can also use the Stream API to perform operations in parallel. In short, the Stream API provides an efficient and easy-to-use way to process data.
[1] What exactly is : ** is a data channel, used to manipulate the sequence of elements generated by the data source (collection, array, etc.). Collections are about data, streams are about computation!
[2] Note: ①, Stream itself will not store data. ②, Stream will not change the source object. Instead, they return a new Stream holding the result. ③, Stream operation is delayed execution. This means they will wait until the result is needed before executing.
[3] There are three steps to the operation of **Stream: 1. Create a Stream A data source (such as a collection, an array), and obtain a stream. ②, intermediate operation: an intermediate operation chain, processing the data of the data source. 3. Termination operation (terminal operation): a termination operation, which executes the chain of intermediate operations and produces the result:
Java8 新特性

default Stream<E> stream()//返回一个顺序流;
default Stream<E> parallelStream()//返回一个并行流;
//举例
Integer[] array = new Integer[]{3,4,8,16,19,27,23,99,76,232,33,96};
numbers.stream().forEach(System.out::println);
});

[5] Create a stream from an array: The static method stream() of Arrays in Java8 can obtain an array stream: static <T> Stream<T> stream(T[] array): Returns a stream; overloaded, can Handle arrays corresponding to primitive types:

public static IntStream stream(int[] array) ;
public static LongStream stream(long[] array) ;
public static DoubleStream stream(double[] array);
//举例
Integer[] array = new Integer[]{3,4,8,16,19,27,23,99,76,232,33,96};
long count = Arrays.stream(array).filter(i->i>20).count();

[6] Create a stream by value : You can use the static method Stream.of() to create a stream by displaying the value. It can receive any number of arguments.

public static<T> Stream<T> of(T... values) : 返回一个流
//举例
Integer[] array = new Integer[]{3,4,8,16,19,27,23,99,76,232,33,96};
long count = Stream.of(array).filter(i->i>20).count();
long sum = Stream.of(12,77,59,3,654).filter(i->i>20).mapToInt(Integer::intValue).sum();

[7] Create a stream by a function : To create an infinite stream, you can use the static methods Stream.iterate() and Stream.generate() to create an infinite stream.

public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f); //迭代
public static<T> Stream<T> generate(Supplier<T> s); //生成
//举例 iterate
Stream<BigInteger> bigIntStream = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.TEN)).limit(10);
BigInteger[] bigIntArr = bigIntStream.toArray(BigInteger[]::new);
//输出:[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
System.out.println(Arrays.toString(bigIntArr));
//举例 generate
Stream<String> stream = Stream.generate(() -> "test").limit(10);
String[] strArr = stream.toArray(String[]::new);
//输出 [test, test, test, test, test, test, test, test, test, test]
System.out.println(Arrays.toString(strArr));
Intermediate operations of Stream: Multiple intermediate operations can be connected to form a pipeline. Unless a termination operation is triggered on the pipeline, the intermediate operations will not perform any processing! When the operation is terminated, it is processed all at once, which is called "lazy evaluation".

[1] screening and slicing :

methoddescribe
filter(Predicate p)Receives a Lambda that excludes certain elements from the stream.
distinct()Filter to remove duplicate elements by hashCode() and equals() of the elements generated by the stream.
limit(long maxSize)Truncates the stream so that it does not exceed the given number of elements.
skip(long n)Skips elements, returning a stream with the first n elements thrown away. If there are fewer than n elements in the stream, an empty stream is returned. Complementary to limit(n).
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
for(Integer i:numbers){
    if(i>20){
        count++;
    }
}
//当使用 Stream 操作时  如下:
list.stream().filter(num -> num > 4).count();
//limit 使用:输出 [1, 2, 3, 4] 方法会返回一个包含n个元素的新的流(若总长小于n则返回原始流)
List<Integer> afterLimit = list .stream().limit(4).collect(Collectors.toList());
//skip(n) 使用:输出 [5, 6, 7, 8, 9] 与limit 正好相反,它会丢弃掉前面的n个元素。
List<Integer> afterSkip = list .stream().skip(4).collect(Collectors.toList());
//用limit和skip方法一起使用就可以实现日常的分页功能
List<Integer> pageList = myList.stream().skip(pageNumber*pageSize)
                  .limit(pageSize).collect(Collectors.toList());

[2] maps :

methoddescribe
map(Function f)Takes a function as an argument, the function will be applied to each element and mapped to a new element.
mapToDouble(ToDoubleFunction f)Receives a function as an argument that will be applied to each element, producing a new DoubleStream.
mapToInt(ToIntFunction f)Receives a function as a parameter that will be applied to each element, producing a new IntStream.
mapToLong(ToLongFunction f)Receives a function as a parameter, the function will be applied to each element, producing a new LongStream.
flatMap(Function f)Takes a function as an argument, replaces each value in the stream with another stream, and concatenates all the streams into a single stream.
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
//将Integer类型转换成String类型
List<String> afterString = integerList.stream().map(i->String.valueOf(i)).collect(Collectors.toList());

[3] sort : The stream conversion methods described above are stateless. That is, when an element is taken from a stream that has been transformed, the result does not depend on the previous element. In addition, there are two methods that need to rely on the elements in the previous stream when transforming the stream. One is the distinct method and the other is the sorted method. The distinct method returns a stream with the same order, with duplicate elements removed, based on the elements in the original stream. This operation obviously requires remembering the previously read elements.

methoddescribe
sorted()Produces a new stream, which is sorted by natural ordering.
sorted(Comparator comp)Produces a new stream that is sorted in comparator order.
//distinct
List<Integer> list = Arrays.asList(70, 25, 38, 64, 25, 46, 7, 18, 9);
List<Integer> distinctList = list.stream().distinct().collect(Collectors.toList());
//sorted 
List<Integer> sortList = myTestList.stream()
                .sorted(Integer::compareTo).collect(Collectors.toList());

Aggregate operations on Streams: Terminal operations produce results from a pipeline of streams. The result can be any value that is not a stream, for example: List, Integer, or even void.
[1] finds and matches :

methoddescribe
allMatch(Predicate p)Check if all elements are matched
anyMatch(Predicate p)Check if at least one element is matched
noneMatch(Predicate p)Check if all elements are not matched
findFirst()The return-first-element terminal operation produces a result from the stream's pipeline. The result can be any value that is not a stream, for example: List, Integer, or even void.
findAny()Returns any element in the current stream
count()Returns the total number of elements in the stream
max(Comparator c)Returns the maximum value in the stream
min(Comparator c)Returns the smallest value in the stream
forEach(Consumer c)Internal iteration (using the Collection interface requires the user to do the iteration, called external iteration. In contrast, the Stream API uses internal iteration - it does the iteration for you)
List<Integer> list = Arrays.asList(70, 125, 38, 64, 25, 46, 7, 18, 9);
//max 与 min 案例
Integer maxItem = list.stream().max(Integer::compareTo).get();
Integer minItem = list.stream().min(Integer::compareTo).get();
//findFirst:方法返回非空集合中的第一个值,它通常与filter方法结合起来使用。
Integer first = list.stream().filter(i->i>100).findFirst().get();
//findAny:可以在集合中只要找到任何一个所匹配的元素,就返回,此方法在对流并行执行时十分有效(任何片段中发现第一个匹配元素都会结束计算,串行流中和findFirst返回一样)。
Integer anyItem = list.parallelStream().filter(i->i>100).findAny().get();
//anyMatch:可以判定集合中是否还有匹配的元素。返回结果是一个boolean类型值。noneMatch 相反。
boolean isHas = list.parallelStream().anyMatch(i->i>100);
boolean noHas = hearList.parallelStream().noneMatch(i->i>100);

[2] :

reduce(T iden, BinaryOperator b)The elements in the stream can be combined repeatedly to get a value. return T
reduce(BinaryOperator b)The elements in the stream can be combined repeatedly to get a value. return Optional<T>
List<Integer> list = Arrays.asList(70, 125, 38, 64, 25, 46, 7, 18, 9);
//简化一下,对元素长度进行求和。
sum = list.stream().map(Objects::toString).mapToInt(String::length).sum();

Note : The connection of map and reduce is often called the map-reduce pattern, famous for Google's use of it for web searches.

[3] collects : After processing the stream, you usually want to look at the results instead of aggregating them into a single value. The Collectorts class provides us with various factory methods of the commonly used collection classes.

methoddescribe
collect(Collector c)Convert the stream to another form. Receives an implementation of the Collector interface, a method for summarizing elements in the Stream.

The implementation of the methods in the Collector interface determines how to perform collection operations on the stream (such as collection to List, Set, Map). However, Collectors uses classes to provide many static methods, which can easily create common collector instances. The specific methods and instances are as follows:

methodreturn typeeffect
toListList<T>Collect the elements in the stream into a List
List<Employee> emps= list.stream().collect(Collectors.toList());
toSetSet<T>Collect elements from the stream into a Set
Set<Employee> emps= list.stream().collect(Collectors.toSet());
toCollectionCollection<T>Collect elements from the stream into the created collection
Collection<Employee>emps=list.stream().collect(Collectors.toCollection(ArrayList::new));
countingLongcount the number of elements in the stream
long count = list.stream().collect(Collectors.counting());
summingIntIntegerSum the integer attributes of elements in a stream
inttotal=list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingIntDoubleCalculates the average of the Integer properties of elements in the stream
doubleavg= list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingIntIntSummaryStatisticsGather statistics for the Integer property in the stream.
IntSummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
joiningStringconcatenate each string in the stream
String str= list.stream().map(Employee::getName).collect(Collectors.joining());
maxByOptional<T>Select the maximum value based on the comparator
Optional<Emp>max= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
minByOptional<T>Select minimum value based on comparator
Optional<Emp> min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
reducingTypes produced by the reductionStarting from an initial value as an accumulator, use BinaryOperator to combine elements in the stream one by one to reduce to a single value
inttotal=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));
collectingAndThenConvert the type returned by the functionWrap another collector and transform the function on its result
inthow= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
groupingByMap<K, List<T>>Group streams according to an attribute value, the attribute is K, and the result is V
Map<Emp.Status, List<Emp>> map= list.stream().collect(Collectors.groupingBy(Employee::getStatus));
partitioningByMap<Boolean, List<T>>Partition based on true or false
Map<Boolean,List<Emp>>vd= list.stream().collect(Collectors.partitioningBy(Employee::getManage));
//例如前面的例子用的要将一个流收集到一个List中,只需要这样写就可以。
List<Integer> thereList = hereList.stream().collect(Collectors.toList());
//收集到Set中可以这样用
Set<Integer> thereSet = hereList.stream().collect(Collectors.toSet());
//将字流中的字符串连接并收集起来。
String resultString = stringList.stream().collect(Collectors.joining());
//在将流中的字符串连接并收集起来时,想在元素中介添加分隔符,传递个joining方法即可。
String resultString = stringList.stream().collect(Collectors.joining(","));
//总和、平均值,最大值,最小值
int sum = hereList.stream().collect(Collectors.summingInt(Integer::intValue));
Double ave = hereList.stream().collect(Collectors.averagingInt(Integer::intValue));
Integer max = hereList.stream().collect(Collectors.maxBy(Integer::compare)).get();
Integer min = hereList.stream().collect(Collectors.minBy(Integer::compare)).get();

[ common ]: Collect the result set into a Map; when we want to collect the elements in the collection into a Map, we can use the Collectors.toMap method. This method has two parameters, which are used to generate the key and value of the Map. For example, the high of a Form object is used as the key width as the value: each toMap method will have a corresponding toConCurrentMap method, which is used to generate a concurrent Map.

//准备工作
List<Form> formList = Lists.newArrayList(
    new Form (3,4,5),
    new Form (6,5,3),
    new Form (77,43,55);
)
//Form对象的 high作为键 width作为值
Map<Integer,Integer> hwMap = formList.stream().collect(Collectors.toMap(Form::getHigh, Form::getWidth));
//但是通常还是以具体元素作为值的情况多,可以使用Function.identity()来获取实际元素。
Map<Integer,Form> FormMap = formList.stream().collect(Collectors.toMap(Form::getHigh, Function.identity()));
//如果多个元素拥有相同的键,在收集结果时会抛出java.lang.IllegalStateException异常。
//可以使用第三个参数来解决,第三个参数用来确定当出现键冲突时,该如何处理结果,如果当出现键冲突时只保留一个并且是保留已经存在的值时,就是如下方式。
Map<Integer,Form> rMap = formList.stream().collect(Collectors.toMap(Form::getHigh, Function.identity(),(nowValue,newValue)->nowValue));
//如果想指定生成的 Map类型,则还需要第三个参数。
TreeMap<Integer,Form> FormTreeMap = FormList.stream().collect(Collectors.toMap(Form::getHigh,
            Function.identity(),(nowValue,newValue)->newValue,TreeMap::new));
//******在一个集合中,对具有相同特性的值进行分组是一个很常见的功能,在Stream的API中也提供了相应的方法。
//根据 high 将 Form 进行分组
Map<Integer,List<Form>> groupMap = list .stream().collect(Collectors.groupingBy(Form::getHigh));
//当分类函数是一个返回布尔值的函数时,流元素会被分为两组列表:一组是返回true的元素集合,另一组是返回false的元素集合。这种情况适用 partitoningBy方法会比groupingBy更有效率。
Map<Boolean,List<Form>> partitionMap = list.stream().collect(Collectors.partitioningBy(form->form.getHigh()==22));
//例如我们将房间集合分为两组,一组是高度为22的房间,另一组是其他房间。
//mapping方法会将结果应用到另一个收集器上。如下取出分组中宽度最大的宽度。
Map<Integer, Optional<Integer>> collect = list.stream().collect(Collectors.groupingBy(Form::getHigh,
                Collectors.mapping(Form::getWidth,Collectors.maxBy(Comparator.comparing(Integer::valueOf)))));
//*****groupingBy是支持多级分组的。例如第一级我们将按照高度分组,第二级按照宽度分组。
Map<Integer,Map<Integer,List<Form>>> multistageMap = list.stream().
        collect(Collectors.groupingBy(Form::getHigh,Collectors.groupingBy(Form::getWidth)));

Parallel stream and serial stream : Parallel stream is a stream that divides a content into multiple data blocks and processes each data block with different threads. Parallelism has been optimized in Java8, and we can easily perform parallel operations on data. The Stream API can declaratively switch between parallel and sequential streams via parallel() and sequential(). But parallel streams also need to be paid attention to when using them. First, it must be a parallel stream, as long as the stream is in parallel mode when the execution of the terminating method is executed, then all stream operations will be executed in parallel.

Stream.of(roomList).parallel();

The parallel method can convert any serial stream into a parallel stream. The second is to ensure that the functions passed to parallel stream operations are thread-safe.

//下面这个例子中的代码就是错误的,传递给并行流的操作并不是线程安全的。可以改为AtomicInteger的对象数组来作为计数器。
int[] words = new int[23];
Stream.of(roomList).parallel().forEach(s->{
     if(s.size()<10){
           words[s.size()]++;
     }
});

We can only show the advantages of parallel streams when processing a large amount of aggregate data, and the purpose is to improve efficiency and utilize the resources of multi-core CPUs while ensuring thread safety. When using the Stream API, when traversing or processing the stream, when referring to an external variable, the variable will be treated as a fianl variable by default. Therefore, some students will feel that the index of the collection cannot be obtained during the traversal process. In fact, you can change the idea to just traverse the collection index, and then get the value in the traversal.

IntStream.range(0,roomList.size()).forEach(i->{       System.out.println(roomList.get(i));});

Fork/Join framework : When necessary, a large task is split (fork) into several small tasks (when it is dismantled until it cannot be split again), and then the results of the operation of the small tasks are processed one by one. join aggregates.
Java8 新特性

The difference between the Fork/Join framework and the traditional thread pool : Adopt "work-stealing" mode ( work-stealing ): When executing a new task, it can split it into smaller tasks for execution, and divide the small tasks into smaller ones. Add to the thread queue, then steal one from a random thread's queue and put it in its own queue. Compared with the general thread pool implementation, the advantage of the fork/join framework is reflected in the processing of the tasks contained in it. In the general thread pool, if a thread is executing the task for some reason
If it cannot continue running, the thread will be in a waiting state. In the implementation of the fork/join framework, if a subproblem cannot continue to run due to waiting for the completion of another subproblem. Then the thread processing the sub-problem will actively look for other sub-problems that have not yet run to execute. In this way, the waiting time of the thread is reduced and the performance is improved.

5. Default methods and static methods in


In Java8, an interface is allowed to contain a method with a concrete implementation, which is called a "default method", and the default method is decorated with the default keyword. For example:

interface MyFunc<T>{
    T func(int a);
    default String getName(){
        return "Hello Java8!";
    }
}

The "class first" principle of interface default method: if an interface defines a default method, and another parent class or interface defines a method with the same name.
[1] Select the method in the parent class. If a superclass provides a concrete implementation, then default methods in the interface with the same name and parameters are ignored.
[2] Interface conflict. If a parent interface provides a default method, and another interface also provides a method with the same name and parameter list (regardless of the method
is the default method), then this method must be overridden to resolve conflicts.
[The "class first" principle of interface default methods] :

interface MyFunc{
    default String getName(){
        return "Hello Java8!";
    }
}
interface Named(){
    default String getName(){
        return "Hello atguigu!";
    }
}
class MyClass implements MyFunc,Named{
    public String getName(){
        return Named.super.getName();
    }
}

[Static methods : In Java8, static methods are allowed to be added to interfaces;

interface Named{
    public Integer myFunc();
    default String getName(){
        return "Hello atguigu!";
    }
    static void show(){
        System.out.println("Hello Lambda!");
    }
}

Six, new time and date API


[1] LocalDate, LocalTime, LocalDateTime: are immutable objects, representing date, time, date and time using the ISO-8601 date system, respectively. It provides a simple date or time and does not contain current time information. Nor does it contain time zone related information.

methoddescribeExample
now()Static method that creates an object based on the current timeLocalDate localDate = LocalDate.now();LocalTime localTime = LocalTime.now();LocalDateTime localDateTime = LocalDateTime.now()
of()Static method that creates an object based on the specified date/timeLocalDate localDate = LocalDate.of(2016, 10, 26); LocalTime localTime = LocalTime.of(02, 22, 56); LocalDateTime localDateTime = LocalDateTime.of(2016, 10, 26, 12, 10, 55);
plusDays,plusWeeks, plusMonths, plusYearsAdd days, weeks, months, years to the current LocalDate object
minusDays, minusWeeks,minusMonths, minusYearsSubtract days, weeks, months, years from the current LocalDate object
plus, minusAdd or subtract a Duration or Period
withDayOfMonth, withDayOfYear, withMonth,withYearModify the number of days in the month, the days in the year, the month, and the year to the specified values and return a new LocalDate object
getDayOfMonthGet the number of days in the month (1-31)
getDayOfYeargetDayOfYear Get the day of the year (1-366)
getDayOfWeekGet the day of the week (returns a DayOfWeek enumeration)
getMonthGet the month, returning a Month enumeration value
getMonthValueget month (1-12)
getYearyear of acquisition
untilGet a Period object between two dates, or specify a number for ChronoUnits
isBefore, isAfterCompare two LocalDates
isLeapYearDetermine if it is a leap year

[2] Instant Timestamp : **Used for "timestamp" operations. It operates on the description of what has been experienced since the first year of Unix (traditionally set to midnight on January 1, 1970 in the UTC time zone);
[3] **Duration and Period: Duration: used to calculate two "time" intervals; Period: used to calculate two "date" intervals;

Instant instant_1 = Instant.now();
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
Instant instant_2 = Instant.now();
Duration duration = Duration.between(instant_1, instant_2);
System.out.println(duration.toMillis());
// 运行结果:1000
LocalTime localTime_1 = LocalTime.now();
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
LocalTime localTime_2 = LocalTime.now();
System.out.println(Duration.between(localTime_1, localTime_2).toMillis());
// 运行结果:1000
LocalDate localDate_1 = LocalDate.of(2018,9, 9);
LocalDate localDate_2 = LocalDate.now();
Period period = Period.between(localDate_1, localDate_2);
System.out.println(period.getYears());      // 运行结果:1
System.out.println(period.getMonths());     // 运行结果:1
System.out.println(period.getDays());       // 运行结果:18

[4] Date manipulation: TemporalAdjuster: time corrector. Sometimes we may need to get operations such as: adjust the date to "next Sunday", etc. TemporalAdjusters: This class provides implementations of a large number of commonly used TemporalAdjusters through static methods. For example to get the next Sunday:

LocalDate nextSunday = LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.SUNDAY));//获取下个周日
LocalDateTime localDateTime1 = LocalDateTime.now();
System.out.println(localDateTime1);     // 2019-10-27T14:19:56.884
// 获取这个第一天的日期
System.out.println(localDateTime1.with(TemporalAdjusters.firstDayOfMonth()));            // 2019-10-01T14:22:58.574
// 获取下个周末的日期
System.out.println(localDateTime1.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)));   

[5] parsing and formatting : java.time.format.DateTimeFormatter class: This class provides three formatting methods:
● predefined standard formats;
● locale-dependent formats;
● custom format;

DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ISO_DATE;
LocalDateTime localDateTime = LocalDateTime.now();
String strDate1 = localDateTime.format(dateTimeFormatter1);
System.out.println(strDate1);
// 运行结果:2019-10-27
// Date -> String
DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd  HH:mm:ss");
String strDate2 = dateTimeFormatter2.format(localDateTime);
System.out.println(strDate2);
// 运行结果:2019-10-27  14:36:11
// String -> Date
LocalDateTime localDateTime1 = localDateTime.parse(strDate2, dateTimeFormatter2);
System.out.println(localDateTime1);
// 运行结果:2019-10-27T14:37:39

[6] time zone processing: Java8 has added support for time zones. The time with time zone is: ZonedDate, ZonedTime, ZonedDateTime. Each time zone corresponds to an ID, and the zone ID is "{zone}/{ City}" format; for example: Asia/Shanghai, etc.;
● ZoneId: This class contains all time zone information;
● getAvailableZoneIds(): can get all time zone time zone information;
● of(id): Get the ZoneId object with the specified time zone information;

// 获取所有的时区
Set<String> set = ZoneId.getAvailableZoneIds();
// 通过时区构建LocalDateTime
LocalDateTime localDateTime1 = LocalDateTime.now(ZoneId.of("America/El_Salvador"));
System.out.println(localDateTime1);
// 2019-10-27T00:46:21.268
// 以时区格式显示时间
LocalDateTime localDateTime2 = LocalDateTime.now();
ZonedDateTime zonedDateTime1 = localDateTime2.atZone(ZoneId.of("Africa/Nairobi"));
System.out.println(zonedDateTime1);
// 2019-10-27T14:46:21.273+03:00[Africa/Nairobi]

[7] and traditional date processing conversion :

kindTo legacy classesFrom legacy class
java.time.Instant java.util.DateDate.from(instant)date.toInstant()
java.time.Instant java.sql.TimestampTimestamp.from(instant)timestamp.toInstant()
java.time.ZonedDateTime java.util.GregorianCalendarGregorianCalendar.from(zonedDateTime)cal.toZonedDateTime()
java.time.LocalDate java.sql.TimeDate.valueOf(localDate)date.toLocalDate()
java.time.LocalTime java.sql.TimeDate.valueOf(localDate)date.toLocalTime()
java.time.LocalDateTime java.sql.TimestampTimestamp.valueOf(localDateTime)timestamp.toLocalDateTime()
java.time.ZoneId java.util.TimeZoneTimezone.getTimeZone(id)timeZone.toZoneId()
java.time.format.DateTimeFormatter java.text.DateFormatformatter.toFormat()none

7. Other new features


[1] Optional class: Optional<T> class (java.util.Optional ) is a container class that represents the existence or non-existence of a value. It used to be null to indicate that a value does not exist. Now Optional can be better express this concept. And can avoid null pointer exception. Common method:
● Optional.of(T t): Create an Optional instance;
● Optional.empty(): create an empty Optional instance;
● Optional.ofNullable(T t): If t is not null, create an Optional instance, otherwise create an empty instance;
● isPresent(): Determine whether it contains a value;
● orElse(T t): If the calling object contains a value, return the value, otherwise return t;
● orElseGet(Supplier s): If the calling object contains a value, return the value, otherwise return the value obtained by s;
● map(Function f): If there is a value to process it, and return the processed Optional, otherwise return Optional.empty();
● flatMap(Function mapper): Similar to map, the return value must be Optional;

public class Java8Tester {
   public static void main(String args[]){
      Java8Tester java8Tester = new Java8Tester();
      Integer value1 = null;
      Integer value2 = new Integer(10);
      // Optional.ofNullable - 允许传递为 null 参数
      Optional<Integer> a = Optional.ofNullable(value1);
      // Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
      Optional<Integer> b = Optional.of(value2);
      System.out.println(java8Tester.sum(a,b));
   }
   public Integer sum(Optional<Integer> a, Optional<Integer> b){
      // Optional.isPresent - 判断值是否存在
      System.out.println("第一个参数值存在: " + a.isPresent());
      System.out.println("第二个参数值存在: " + b.isPresent());
      // Optional.orElse - 如果值存在,返回它,否则返回默认值
      Integer value1 = a.orElse(new Integer(0));
      //Optional.get - 获取值,值需要存在
      Integer value2 = b.get();
      return value1 + value2;
   }
}
//输出结果:
第一个参数值存在: false
第二个参数值存在: true
10

[2] Duplicate annotations and type annotations : Java8 provides two improvements to annotation processing, repeatable annotations and annotations that can be used for types. Custom repeatable annotation as follows: use @Repeatable meta-annotation, the parameter is the container of repeatable annotation.

@Repeatable(MyAnnotations.class)
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "java8";
}
/**
 * 容器类
 */
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RepetitionAnnotations {
    RepetitionAnnotation[] value();
}

Test Method

public class AnnotationTest {
    @Test
    public void t1() throws Exception {
        Class<AnnotationTest> clazz = AnnotationTest.class;
        Method method = clazz.getMethod("show");
        // 获取方法上的注解
        RepetitionAnnotation[] ras = method.getAnnotationsByType(RepetitionAnnotation.class);
        for (RepetitionAnnotation repetitionAnnotation : ras) {
            System.out.println(repetitionAnnotation.value());
        }
    }
    @RepetitionAnnotation("Hello")
    @RepetitionAnnotation("World")
    public void show() {
    }
}

[ type annotation ]

//就是向 @Target 添加一种类型 TYPE_PARAMETER
@Repeatable(RepetitionAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface RepetitionAnnotation {
    String value() default "ling";
}
//使用
@RepetitionAnnotation("Hello")
@RepetitionAnnotation("World")
public void show(@RepetitionAnnotation String str) {}

Article source: https://javajgs.com/archives/8246

Seeing here today's sharing is over. If you think this article is not bad, come to share, like, and watch Sanlian, so that more people can see it~

Welcome to pay attention to the personal public "JavaClub" , and regularly share some technical dry goods for you.


阿福研习社
57 声望43 粉丝