java8新特性学习笔记

本文详细介绍了Java 8的主要新特性,包括Lambda表达式的使用,简化代码的Stream API,以及新的日期时间API。Lambda表达式提供了匿名内部类的简洁替代,Stream API提供了高效的数据处理方式,如过滤、映射和归约操作。新日期时间API解决了旧API的线程安全问题。此外,文章还提到了接口的默认方法、重复注解和类型注解等其他特性。
摘要由CSDN通过智能技术生成

目录

目录

1、速度更快

2、Lambda表达式

2.1、匿名内部类的Lambda转换

2.2、java8内置的四大核心函数式接口

2.3、方法引用和构造器

2.3.1、方法引用

2.3.2、构造器引用​编辑

2.3.3、数组引用

3、Stream API

3.1、stream API常用例子

3.2、stream映射

3.2.1、map

3.2.2、flatMap

3.3、stream排序与查找

3.4、map-reduce

3.5、collection

3.6、steamAPI练习

3.7、java8根据某一个字段分组求和

3.8、java8根据某两个字段分组求和

4、并行流

4.1、fork/join框架

4.2、顺序流与并行流比较

5、接口中的默认方法

 6、新时间日期api

7、重复注解与类型注解

7.1、重复注解

 7.2、类型注解

8、总结

9、参考资料 



1、速度更快

jdk1.8对底层做了优化,使得速度更快了。jdk1.8取消了永久区,取而代之的是增加了元空间(MetaSpace),元空间直接使用了物理内存(RAM),因此运行速度会更快。

 jdk1.8之后对哈希表做了优化,在jdk1.8之前,哈希表的结构是数组+链表,jdk1.7使用的是头插法,jdk1.7用的单链表是纵向延伸的。jdk1.8之后,增加了红黑树,jdk1.8之后的哈希表的结构是数组+链表+红黑树。jdk1.8的哈希表用的是尾插法,当哈希表容量达到总容量的3/4的时候(负载因子0.75),会进行扩容,扩容后的大小为当前容量*2。当哈希表中某个表项上面串的那一个单链表长度大于8的时候,这个单链表会转为红黑树。有关jdk1.8后的哈希表更多了解可以参考以下三篇文章

JDK1.8 HashMap的默认长度与扩容分析_zyt_ java的博客-CSDN博客

JDK1.8之HashMap扩容分析 - 怂人不倦 - 博客园

jdk1.8 HashMap工作原理和扩容机制(源码解析)_青元子的博客-CSDN博客_hashmap1.8扩容

2、Lambda表达式

Lambda表达式可以简化代码,尤其是对于需要使用到匿名内部类的。Lambda是一个匿名函数,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。

Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->”, 该操作符被称为 Lambda 操作符或剪头操作符。

它将 Lambda 分为两个部分:
左侧:指定了 Lambda 表达式需要的所有参数
右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能

语法格式:

2.1、匿名内部类的Lambda转换

//匿名内部类
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("HHH");
            }
        };
        r1.run();

        //lambda表达式
        Runnable r2 = () -> {
            System.out.println("HHH");
        };
        r2.run();

2.2、java8内置的四大核心函数式接口

定义:只包含一个抽象方法的接口称为“函数式接口”,通常在接口方法上用@FunctionalInterface修饰。

java8中四大函数式接口

  • Consumer<T>:消费型接口  void accept(T t);
  • Supplier<T>:供给型接口  T get();
  • Function<T,R>:函数型接口  R apply(T t);
  • Predicate<T>:boolean test(T t);
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * @author: wu linchun
 * @time: 2021/8/15 15:26
 * @description:
 */

public class TestLambda02 {
    public static void main(String[] args) {
        //消费型接口:Consumer<T>  有参数,无返回值类型的接口
        testConsumer(10000, (m) -> {
            System.out.println(m);
        });

        //函数型接口:Function<T,R>  输入一个类型得参数,输出一个类型得参数,当然两种类型可以一致
        System.out.println(testFunction("abc", (f) -> {
            return f.toUpperCase();
        }));

        //供给型接口:Supplier<T>  只有产出,没人输入,就是只有返回值,没有入参
        System.out.println(testSupplier(10, () -> {
            return (int) (Math.random() * 100);
        }));


        //断言型接口:Predicate<T>  输入一个参数,输出一个boolean类型得返回值
        List<String> list = Arrays.asList("asadax", "a", "cv", "bcv", "asaqs", "fksix", "ls9821");
        System.out.println(testPredicate(list, (l) -> {
            return l.length() > 3;
        }));
    }

    //消费型接口:Consumer<T>  有参数,无返回值类型的接口
    public static void testConsumer(double money, Consumer<Double> con) {
        con.accept(money);
    }

    //函数型接口:Function<T,R>  输入一个类型得参数,输出一个类型得参数,当然两种类型可以一致
    public static String testFunction(String str, Function<String, String> fun) {
        return fun.apply(str);
    }

    //供给型接口:Supplier<T>  只有产出,没人输入,就是只有返回值,没有入参
    public static List<Integer> testSupplier(int num, Supplier<Integer> sup) {
        List<Integer> list = new ArrayList<>(num);
        for (int i = 0; i < num; i++) {
            list.add(sup.get());
        }
        return list;
    }

    //断言型接口:Predicate<T>  输入一个参数,输出一个boolean类型得返回值
    public static List<String> testPredicate(List<String> list, Predicate<String> pre) {
        List<String> strlist = new ArrayList<>();
        for (String s : list) {
            if (pre.test(s)) {
                strlist.add(s);
            }
        }
        return strlist;
    }
}

2.3、方法引用和构造器

2.3.1、方法引用

import entity.Student;

import java.util.*;
import java.util.function.*;

/**
 * @author: wu linchun
 * @time: 2021/8/16 14:26
 * @description:
 */

public class TestLambda03 {
    public static void main(String[] args) {
        Student student = new Student("张三", 100, 20);
        Supplier<String> stringSupplier = () -> student.getName();
        System.out.println("姓名:" + stringSupplier.get());

        //对象::实例方法名
        Supplier<Integer> stringSupplier1 = student::getAge;
        System.out.println("年龄:" + stringSupplier1.get());


        List<Integer> list = Arrays.asList(1, 2, 4, 32, 23, 100, 32, 400, 20);
        List<Integer> list1 = Arrays.asList(1, 2, 4, 32, 23, 100, 32, 400, 20);
        Comparator<Integer> comparator = (x, y) ->
        {
            return Integer.compare(x, y);
        };
        //类::静态方法名
        Comparator<Integer> comparator1 = Integer::compare;
        Collections.sort(list, comparator);
        Collections.sort(list1, comparator1);
        for (int i : list) {
            System.out.print(i + ",");
        }
        System.out.println();
        for (int i : list1) {
            System.out.print(i + ",");
        }

        System.out.println();
        BiPredicate<String, String> ff = (x, y) -> x.equals(y);
        //类::实例方法名
        BiPredicate<String, String> ff1 = String::equals;
        System.out.println(ff.test("aa", "aa"));
        System.out.println(ff.test("aa", "bb"));
        System.out.println(ff1.test("aa", "aa"));
        System.out.println(ff1.test("aa", "bb"));


    }
}

2.3.2、构造器引用

import entity.Student;

import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author: wu linchun
 * @time: 2021/8/16 18:02
 * @description:
 */

public class TestLambda05 {
    public static void main(String[] args) {
        Student student = new Student("张三", 100, 20);
        Supplier<Student> supplier = () -> student;
        Supplier<Student> supplier1 = Student::new;
        //构造器引用
        Function<String, Student> function = Student::new;
        Function<Integer, Student> function1 = Student::new;
        Student student1 = function.apply("李四");
        Student student2 = function1.apply(20);
        System.out.println(supplier.get());
        System.out.println(supplier1.get());
        System.out.println(student1);
        System.out.println(student2);
    }
}

2.3.3、数组引用

import java.util.function.Function;

/**
 * @author: wu linchun
 * @time: 2021/8/16 17:55
 * @description:
 */

public class TestLambda04 {
    public static void main(String[] args) {
        Function<Integer, String[]> fun = (x) -> new String[x];
        //数组引用:Type[]:new
        Function<Integer, String[]> fun1 = String[]::new;
        String[] s1 = fun.apply(10);
        String[] s2 = fun1.apply(20);
        System.out.println(s1.length);
        System.out.println(s2.length);
    }
}

3、Stream API

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

Stream流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算!”

注意:

  • Stream 自己不会存储元素。
  • Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  • Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

 Stream 的操作三个步骤

  • 创建 Stream:一个数据源(如:集合、数组),获取一个流
  • 中间操作:一个中间操作链,对数据源的数据进行处理
  • 终止操作:一个终止操作,执行中间操作链,并产生结果

3.1、stream API常用例子

import entity.Student;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author: wu linchun
 * @date: 2021/08/17/13:55
 * @Description:
 **/
public class TestLambdaStream01 {
    public static void main(String[] args) {
        Student s1 = new Student("张三", 20, 100);
        Student s2 = new Student("李四", 22, 100);
        Student s3 = new Student("王五", 23, 100);
        Student s4 = new Student("赵六", 24, 100);
        Student s5 = new Student("赵7", 19, 100);
        Student s6 = new Student("赵8", 18, 100);
        Student s7 = new Student("张三", 20, 100);
        List<Student> list = Arrays.asList(s1, s2, s3, s4, s5, s6, s7);

        //filter:从流中排除某些元素
        Stream<Student> studentStreams = list.stream().filter(e -> {
            return e.getAge() <= 20;
        });
        list.forEach(System.out::print);
        System.out.println();
        studentStreams.forEach(System.out::print);
        System.out.println();

        //limit(n):截断流,使元素不超过给定的数量n
        Stream<Student> studentStream01 = list.stream().limit(2);
        studentStream01.forEach(System.out::print);
        System.out.println();

        //skip(n):跳过前n个元素
        Stream<Student> studentStream02 = list.stream().skip(3);
        studentStream02.forEach(System.out::print);
        System.out.println();

        //distinct:去重重复的元素
        Stream<Student> studentStream03 = list.stream().distinct();
        studentStream03.forEach(System.out::print);
        System.out.println();

        //stream转list collect(Collectors.toList())
        List<Student> studentList = list.stream().limit(3).collect(Collectors.toList());
        studentList.forEach(System.out::print);
        System.out.println();

        //数组[]转stream:数组创建流
        Student[] students = {s1, s2, s3, s4, s5, s6, s7};
        Stream<Student> studentStream04 = Arrays.stream(students);
        studentStream04.forEach(System.out::print);
        System.out.println();

        //stream.of:值创建流
        Stream<Student> studentStream05 = Stream.of(s1, s2, s3, s4, s5, s6, s7);
        studentStream05.forEach(System.out::print);
        System.out.println();

        //stream无限流  如果不加限制则会无限输出
        Stream<Integer> stream = Stream.iterate(0, e -> e + 2);
        stream.limit(20).forEach(System.out::println);

    }
}

 stream中内部迭代由stream API完成forEach(),这点是区别于外部迭代的。

//外部迭代
        Iterator<Student> iterator = list.listIterator();
        while (iterator.hasNext()) {
            System.out.print(iterator.next());
        }

3.2、stream映射

3.2.1、map

map可以用来接收lambda表达式,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * @author: wu linchun
 * @time: 2021/8/18 21:05
 * @description:
 */

public class TestLambda06 {
    public static void main(String[] args) {
        // map
        List<String> list = Arrays.asList("aaa", "bbb", "vvv", "Eva", "rrr");
        list.stream().map(s -> s.toUpperCase()).forEach(System.out::println);
        System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");

        Stream<Stream<Character>> stream = list.stream().map(TestLambda06::filterCharacter);
        //stream只能被使用一次,如果连续执行一个对象的stream 就报错了
        //stream.forEach(System.out::print);
        //stream.close();
        System.out.println();
        stream.forEach(s -> s.forEach(System.out::print));
    }

    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<>();
        for (Character c : str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }
}

3.2.2、flatMap

flatMap可以接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * @author: wu linchun
 * @time: 2021/8/19 22:19
 * @description:
 */

public class TestLambda07 {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("asawaxgd", "qw", "rthaacxdf", "paaaolmjh", "laalik", "aaq", "e", "ww");
        Stream<Character> stream = list.stream().flatMap(TestLambda07::filterStream);
        stream.forEach(System.out::println);
    }

    public static Stream<Character> filterStream(String str) {
        List<Character> list = new ArrayList<>();
        for (Character c : str.toCharArray()) {
            if (c.equals('a')) {
                list.add(c);
            }
        }
        return list.stream();
    }
}

简单来说,map和flatMap是对数组流的拆解和合并,具体应用为对数组进行分类再输出。

3.3、stream排序与查找

  • allMatch:检查是否匹配所有元素。
  • anyMatch:检查是否至少匹配一个元素。
  • noneMatch:检查是否没有匹配所有元素。
  • findFirst:返回第一个元素。
  • findAny:返回当前流中的任意一个元素(如果是串行并且数据量较少的情况下,是会返回第一个元素。但是如果是并行的话,就不一定是返回第一个,而是可能是随机的。
  • count:返回流中元素的总个数。
  • max:返回流中最大值。
  • min:返回流中最小值。
import entity.Teacher;
import enums.Status;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * @author: wu linchun
 * @time: 2021/8/20 9:59
 * @description:
 */

public class TestLambda09 {
    public static void main(String[] args) {
        List<Teacher> list = Arrays.asList(
                new Teacher("n1", 20, Status.FREE.getContent()),
                new Teacher("n2", 21, Status.BUSY.getContent()),
                new Teacher("n3", 22, Status.FREE.getContent()),
                new Teacher("n4", 24, Status.BUSY.getContent()),
                new Teacher("n5", 23, Status.FREE.getContent()),
                new Teacher("n6", 20, Status.FREE.getContent()));
        //allMatch:检查是否匹配所有元素
        boolean b1 = list.stream().allMatch((e) -> e.getStatus().equals(Status.BUSY.getContent()));
        //anyMatch:检查是否至少匹配一个元素
        boolean b2 = list.stream().anyMatch((e) -> e.getStatus().equals(Status.BUSY.getContent()));
        //noneMatch:检查是否没有匹配所有元素
        boolean b3 = list.stream().noneMatch((e) -> e.getStatus().equals(Status.VOCATION.getContent()));
        //findFirst:返回第一个元素
        Optional<Teacher> opf = list.stream().findFirst();
        //findAny:返回当前流中的任意一个元素(如果是串行并且数据量较少的情况下,是会返回第一个元素。
        //但是如果是并行的话,就不一定是返回第一个,而是可能是随机的
        Optional<Teacher> opn = list.stream().findAny();
        Optional<Teacher> opn1 = list.parallelStream().findAny();
        //count:返回流中元素的总个数
        long count = list.stream().count();
        //max:返回流中最大值
        Optional<Teacher> opm = list.stream().max((e1, e2) -> {
            return Integer.compare(e1.getAge(), e2.getAge());
        });
        //min:返回流中最小值
        Optional<Teacher> opm1 = list.stream().min((e1, e2) -> {
            return Integer.compare(e1.getAge(), e2.getAge());
        });
        System.out.println(b1);
        System.out.println(b2);
        System.out.println(b3);
        System.out.println(opf.get());
        System.out.println(opn.get());
        System.out.println(opn1.get());
        System.out.println(count);
        System.out.println(opm.get());
        System.out.println(opm1.get());
    }
}

3.4、map-reduce

reduce:归约,可将流中的元素反复结合起来得到一个值。

import entity.Student;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * @author: wu linchun
 * @time: 2021/8/20 22:17
 * @description:
 */

public class TestLambda11 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        //reduce:归约,相当于 0 +1+2+3+4+5+6+7+8+9+10=55
        int num = list.stream().reduce(0, (x, y) -> x + y);
        System.out.println(num);
        System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        List<Student> studentList = Arrays.asList(
                new Student("张三", 20, 100),
                new Student("李四", 21, 61),
                new Student("王五", 16, 40),
                new Student("赵六", 17, 77),
                new Student("ttt", 22, 90),
                new Student("sss", 19, 88)
        );
        //map-reduce: map为获取list中每个对象的指定元素,reduce会操作这些元素进行一些操作
        Optional<Integer> op = studentList.stream().map(Student::getScore).reduce(Integer::sum);
        System.out.println(op.get());
    }
}

3.5、collection

collection:收集,即把stream流转为其他形式,属于stream流的终止操作。

import entity.Student;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: wu linchun
 * @time: 2021/8/21 10:22
 * @description:
 */

public class TestLambda12 {
    public static void main(String[] args) {
        List<Student> studentList = Arrays.asList(
                new Student("张三", 20, 100),
                new Student("李四", 21, 61),
                new Student("王五", 16, 40),
                new Student("赵六", 17, 77),
                new Student("ttt", 22, 90),
                new Student("sss", 19, 90)
        );
        //collect:计算总数
        long count = studentList.stream().collect(Collectors.counting());
        //collect:计算平均值
        double averageAge = studentList.stream().collect(Collectors.averagingDouble(Student::getAge));
        //collect:求和
        double sumGrade = studentList.stream().collect(Collectors.summingDouble(Student::getScore));
        //collect:分组,相同的成绩为一组
        Map<Integer, Map<String, List<Student>>> map = studentList.stream().collect(Collectors.groupingBy(Student::getScore, Collectors.groupingBy((e) -> {
            switch (e.getScore() / 10) {
                case 10:
                    return "A";
                case 9:
                    return "A";
                case 8:
                    return "B";
                case 7:
                    return "C";
                default:
                    return "D";
            }
        })));
        //collect:分区  按年龄是否大于20进行分区
        Map<Boolean, List<Student>> map1 = studentList.stream().collect(Collectors.partitioningBy((e) ->
                e.getAge() > 20));
        //collect:找最大值
        Optional<Student> op = studentList.stream().collect(Collectors.maxBy((e1, e2) -> {
            return Double.compare(e1.getScore(), e2.getScore());
        }));
        //collect:最小值
        Optional<Student> op1 = studentList.stream().collect(Collectors.minBy((e1, e2) -> {
            return Double.compare(e1.getScore(), e2.getScore());
        }));
        //collect:转为list
        List<String> nameList = studentList.stream().map(Student::getName).collect(Collectors.toList());
        //collect:转为set
        Set<String> nameSet = studentList.stream().map(Student::getName).collect(Collectors.toSet());
        //collect:转为hashset   Collectors.joining(分隔符,前缀,后缀)
        HashSet<String> nameHs = studentList.stream().map(Student::getName).collect(Collectors.toCollection(HashSet::new));
        String nameStr = studentList.stream().map(Student::getName).collect(Collectors.joining(",", "<-", "->"));
        //collect:汇总 最大值,最小值,平均值,总数,总和
        DoubleSummaryStatistics dss = studentList.stream().collect(Collectors.summarizingDouble(Student::getAge));
        System.out.println(count);
        System.out.println(averageAge);
        System.out.println(sumGrade);
        for (Map.Entry<Integer, Map<String, List<Student>>> entry : map.entrySet()) {
            System.out.println(entry.getKey() + "——>" + entry.getValue());
        }
        System.out.println("~~~~~~~~~~~~~~~~~~~");
        for (Map.Entry<Boolean, List<Student>> entry : map1.entrySet()) {
            System.out.println(entry.getKey() + "——>" + entry.getValue());
        }
        System.out.println(op.get());
        System.out.println(op1.get());
        System.out.println(nameList.toString());
        System.out.println(nameSet);
        System.out.println(nameHs);
        System.out.println(nameStr);
        System.out.println(dss.getMax() + " " + dss.getMin() + " " + dss.getAverage() + " " + dss.getCount() + " " + dss.getSum());
    }
}

3.6、steamAPI练习

import com.sun.org.apache.bcel.internal.generic.ARETURN;
import entity.Student;
import entity.Trader;
import entity.Transaction;
import org.junit.Before;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;

/**
 * @author: wu linchun
 * @time: 2021/8/21 11:38
 * @description:
 */

public class MyPractise {
    List<Transaction> transactions = null;

    @Before
    public void before() {
        Trader raoul = new Trader("Raoul", "Cambridge");
        Trader mario = new Trader("Mario", "Milan");
        Trader alan = new Trader("Alan", "Cambridge");
        Trader brian = new Trader("Brian", "Cambridge");

        transactions = Arrays.asList(
                new Transaction(brian, 2011, 300),
                new Transaction(raoul, 2012, 1000),
                new Transaction(raoul, 2011, 400),
                new Transaction(mario, 2012, 710),
                new Transaction(mario, 2012, 700),
                new Transaction(alan, 2012, 950)
        );
    }

    @Test
    public void ex1() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        list.stream().map((e) -> {
            return e * e;
        }).forEach(System.out::println);
        System.out.println(list.stream().collect(Collectors.counting()));
    }

    @Test
    public void ex2() {
        List<Student> studentList = Arrays.asList(
                new Student("张三", 20, 100),
                new Student("李四", 21, 61),
                new Student("王五", 16, 40),
                new Student("赵六", 17, 77),
                new Student("ttt", 22, 90),
                new Student("sss", 19, 90)
        );
        studentList.stream().filter(e -> {
            return e.getScore() >= 90;
        }).sorted((e1, e2) -> {
            return -Integer.compare(e1.getScore(), e2.getScore());
        }).forEach(System.out::println);
    }

    //1. 找出2011年发生的所有交易, 并按交易额排序(从低到高)
    @Test
    public void ex3() {
        transactions.stream().filter((e) -> e.getYear() == 2011).sorted((e1, e2) -> {
            return Integer.compare(e1.getValue(), e2.getValue());
        }).forEach(System.out::println);
    }

    //2. 交易员都在哪些不同的城市工作过?
    @Test
    public void ex4() {
        transactions.stream().map((e) -> {
            return e.getTrader().getCity();
        }).distinct().forEach(System.out::println);
    }

    //3. 查找所有来自剑桥的交易员,并按姓名排序
    @Test
    public void ex5() {
        transactions.stream().filter((e) -> {
            return e.getTrader().getCity().equals("Cambridge");
        }).sorted((n1, n2) -> {
            return n1.getTrader().getName().compareTo(n2.getTrader().getName());
        }).forEach(System.out::println);
    }

    //4. 返回所有交易员的姓名字符串,按字母顺序排序
    @Test
    public void ex6() {
        System.out.println(transactions.stream().map((e) -> e.getTrader().getName()).sorted((e1, e2) -> {
            return e1.compareTo(e2);
        }).collect(Collectors.joining(",")));
    }

    //5. 有没有交易员是在米兰工作的?
    @Test
    public void ex7() {
        System.out.println(transactions.stream().map((e) -> e.getTrader().getCity()).anyMatch((e) -> {
            return e.equals("Milan");
        }));
    }

    //6. 打印生活在剑桥的交易员的所有交易额
    @Test
    public void ex8() {
        System.out.println(transactions.stream().filter((e) -> e.getTrader().getCity().equals("Cambridge")).collect(Collectors.summingInt((e) -> e.getValue())));
    }

    //7. 所有交易中,最高的交易额是多少
    @Test
    public void ex9() {
        System.out.println(transactions.stream().collect(Collectors.maxBy((e1, e2) -> {
            return Integer.compare(e1.getValue(), e2.getValue());
        })).get());
    }

    //8. 找到交易额最小的交易
    @Test
    public void ex10() {
        System.out.println(transactions.stream().collect(Collectors.minBy((e1, e2) -> {
            return Integer.compare(e1.getValue(), e2.getValue());
        })));
    }
}

3.7、java8根据某一个字段分组求和

 @Test
    public void testSum() {
        AAA a1 = new AAA("01", 20);
        AAA a2 = new AAA("01", 30);
        AAA a3 = new AAA("01", 40);
        AAA a4 = new AAA("02", 20);
        AAA a5 = new AAA("02", 200);
        AAA a6 = new AAA("02", 120);

        List<AAA> aaaList = Arrays.asList(a1, a2, a3, a4, a5, a6);

        //先分组
        Map<String, List<AAA>> map = aaaList.stream().collect(Collectors.groupingBy(AAA::getTeamId, Collectors.toList()));
        Set<Map.Entry<String, List<AAA>>> ss = map.entrySet();
        List<AAA> list = new ArrayList<>();
        //再求和
        for (Map.Entry<String, List<AAA>> mm : ss) {
            //System.out.println(mm.getKey() + "---" + mm.getValue());
            AAA bb = new AAA(mm.getKey(), mm.getValue().stream().collect(Collectors.summingInt(AAA::getMoney)));
            list.add(bb);
        }
        list.forEach(a -> {
            System.out.println(a.toString1());
        });

    }

    class AAA {
        String teamId;
        Integer money;

        AAA() {
        }

        AAA(String teamId, Integer money) {
            this.teamId = teamId;
            this.money = money;
        }

        String getTeamId() {
            return this.teamId;
        }

        Integer getMoney() {
            return this.money;
        }

        void setTeamId(String teamId) {
            this.teamId = teamId;
        }

        void setMoney(Integer money) {
            this.money = money;
        }

        String toString1() {
            return "[AAA:teamId=" + this.teamId + ",money=" + this.money + "]";
        }

    }

3.8、java8根据某两个字段分组求和

 @Test
    public void testSum() {
        AAA a1 = new AAA("001", "5", new BigDecimal(20));
        AAA a2 = new AAA("001", "5", new BigDecimal(30));
        AAA a3 = new AAA("001", "5", new BigDecimal(40));
        AAA a4 = new AAA("002", "5", new BigDecimal(20));
        AAA a5 = new AAA("002", "5", new BigDecimal(200));
        AAA a6 = new AAA("002", "5", new BigDecimal(120));
        AAA a7 = new AAA("001", "6", new BigDecimal(20));
        AAA a8 = new AAA("001", "6", new BigDecimal(30));
        AAA a9 = new AAA("001", "6", new BigDecimal(40));
        AAA a10 = new AAA("002", "6", new BigDecimal(20));
        AAA a11 = new AAA("002", "6", new BigDecimal(200));
        AAA a12 = new AAA("002", "6", new BigDecimal(120));

        List<AAA> aaaList = Arrays.asList(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);

        //先根据Team,Time分组
        Map<String, List<AAA>> map1 = aaaList.stream().collect(Collectors.groupingBy(aaa -> aaa.getTeamId() + "," + aaa.getTime()));
        Set<Map.Entry<String, List<AAA>>> ss = map1.entrySet();
//        map1.forEach((k, v) -> {
//            System.out.println(k + "->" + v);
//        });

        List<AAA> list = new ArrayList<>();
        //再求和
        for (Map.Entry<String, List<AAA>> mm : ss) {
            //System.out.println(mm.getKey() + "--->" + mm.getValue().toString());
            String[] arr = mm.getKey().split(",");
            AAA bb = new AAA(arr[0], arr[1], mm.getValue().stream().collect(CollectorsUtils.summingBigDecimal(AAA::getMoney)));
            list.add(bb);
        }
        list.forEach(a -> {
            System.out.println(a.toString());
        });

    }

    class AAA {
        String teamId;
        String time;
        BigDecimal money;

        AAA() {
        }

        AAA(String teamId, String time, BigDecimal money) {
            this.teamId = teamId;
            this.time = time;
            this.money = money;
        }

        String getTeamId() {
            return this.teamId;
        }

        BigDecimal getMoney() {
            return this.money;
        }

        String getTime() {
            return this.time;
        }

        void setTeamId(String teamId) {
            this.teamId = teamId;
        }

        void setMoney(BigDecimal money) {
            this.money = money;
        }

        void setTime(String time) {
            this.time = time;
        }

        public String toString() {
            return "[AAA:teamId=" + this.teamId + ",time=" + this.time + ",money=" + this.money + "]";
        }

    }

4、并行流

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。java8对并行流进行了优化,封装了fork/join框架。在java8中,Stream API 可以声明性地通过 parallel() 与
sequential() 在并行流与顺序流之间进行切换。

4.1、fork/join框架

fork/join框架会把大的任务拆分成一个个小任务,再分别把每个小任务分配到不同的线程中,形成一个个线程队列。

不过fork/join和传统的线程池有所区别的是,fork/join框架新增了“工作窃取”模式。执行快的线程在其当前线程队列里面的任务执行完成后,会随机从其他还没有执行完的线程队列队尾“偷”一个放到自己的线程队列中执行(自己没有任务了,就去偷别人的,最大限度的利用cpu)。

fork/join框架只在数据足够多的时候才会体现出其优越性,因为任务拆分是需要消耗时间的,因此如果数据不多,那与顺序流单线程相比没有太多优势。

4.2、顺序流与并行流比较

从0加到1000000000L

1、顺序流

public class TestLambda13 {
    public static void main(String[] args) {
        Instant start1 = Instant.now();
        long sum = 0;
        //从0累加到1000000000L
        for (int i = 0; i <= 1000000000L; i++) {
            sum += i;
        }
        System.out.println(sum);
        Instant end1 = Instant.now();
        System.out.println("顺序流耗费时间:" + Duration.between(start1, end1).toMillis());
    }
}

 可以看到顺序流,cpu执行一个线程去处理,对cpu的利用率不高。

2、并行流

public class TestLambda13 {
    public static void main(String[] args) {
        Instant start = Instant.now();
        //从0累加到1000000000L
        System.out.println(LongStream.rangeClosed(0, 1000000000L).parallel().reduce(0, Long::sum));
        Instant end = Instant.now();
        System.out.println("并行流耗费时间:" + Duration.between(start, end).toMillis());
    }
}

 

 可以看到并行流,会最大化的去利用cpu。

5、接口中的默认方法

在java8之前,接口Interface里面是只能写方法体,不能写方法实现的。但在java8之后,允许在接口中写默认(default)方法的实现。

如下:

public interface MyInterface {
    default String getXXX() {
        return "xxx";
    }

    default String getYYY() {
        return "yyy";
    }
}

在接口的实现方法中,如果不重写接口中的默认方法,那么就会直接使用接口中已经写好的默认方法。

public class MyInterfaceImpl implements MyInterface {
    @Override
    public String getXXX() {
        return MyInterface.super.getXXX();
    }

    @Override
    public String getYYY() {
        return MyInterface.super.getYYY();
    }
}
public class TestLambda14 {
    public static void main(String[] args) {
        System.out.println(new MyInterfaceImpl().getXXX());
        System.out.println(new MyInterfaceImpl().getYYY());
    }
}

当然,如果在接口实现类中重写了接口的默认方法,那么接口中的相应方法会被忽略。

public class MyInterfaceImpl implements MyInterface {
    @Override
    public String getXXX() {
        return "ZZZ";
    }

    @Override
    public String getYYY() {
        return "AAA";
    }
}

 

 6、新时间日期api

java8以后的时间日期api是线程安全的,在java8之前的时间日期api是非线程安全的。

LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。

Instant时间戳用于“时间戳”的运算,它是以Unix元年(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算。

  • Duration:用于计算两个“时间”间隔。
  • Period:用于计算两个“日期”间隔。

DateTimeFormatter用于日期格式化。

public class TestLambda15 {
    public static void main(String[] args) {
        //获取当前日期时间
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);

        //自定义日期时间
        LocalDateTime ldt1 = LocalDateTime.of(2020, 10, 20, 12, 25, 33, 12);
        System.out.println(ldt1);

        //年月日加一
        LocalDateTime ldt2 = ldt1.plusYears(1).plusMonths(1).plusDays(1).plusHours(1);
        System.out.println(ldt2);

        //获取当前时间戳
        Instant start = Instant.now();
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Instant end = Instant.now();
        //Duration:计算两个“时间”之间的间隔
        System.out.println(Duration.between(start, end).toMillis());
        //Period:计算两个“日期”之间的间隔
        LocalDate ld1 = LocalDate.of(2015, 8, 12);
        LocalDate ld2 = LocalDate.now();
        System.out.println(Period.between(ld1, ld2).getYears());

        //格式化时间日期
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
        System.out.println(dateTimeFormatter.format(ldt));

    }
}

7、重复注解与类型注解

7.1、重复注解

在java8中新增了一个注解@Repeatable,允许同一个注解在同一个地方被使用多次。

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
//RUNTIME:允许这个注解被反射,注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {
    MyAnnotation[] value();
}
@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
//RUNTIME:允许这个注解被反射,注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value();
}
import annotation.MyAnnotation;
import annotation.MyAnnotation_01;

import java.lang.reflect.Method;

/**
 * @author: wu linchun
 * @time: 2021/8/21 22:37
 * @description:
 */

public class TestLambda16 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        Class c = Class.forName("TestLambda16");
        Method method1 = c.getMethod("showTwo");
        MyAnnotation[] myAnnotation1 = method1.getAnnotationsByType(MyAnnotation.class);
        for (MyAnnotation myAnnotation : myAnnotation1) {
            System.out.print(myAnnotation.value() + " ");
        }
    }


    @MyAnnotation("Hello")
    @MyAnnotation("World")
    public static void showTwo() {
    }
}

 7.2、类型注解

TYPE_PARAMETER即类型注解,可以注解各种java类型(int,String,数组......)。

@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER})
//RUNTIME:允许这个注解被反射,注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value();
}
import annotation.MyAnnotation;
import annotation.MyAnnotation_01;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @author: wu linchun
 * @time: 2021/8/21 22:37
 * @description:
 */

public class TestLambda16 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        Class c = Class.forName("TestLambda16");
        Method method1 = c.getMethod("showTwo", String.class);
        //获取方法注解
        MyAnnotation[] myAnnotation1 = method1.getAnnotationsByType(MyAnnotation.class);
        for (MyAnnotation myAnnotation : myAnnotation1) {
            System.out.print(myAnnotation.value() + " ");
        }
        System.out.println();
        //获取参数注解
        Annotation[][] myAnnotation2 = method1.getParameterAnnotations();
        System.out.println(myAnnotation2[0][0]);

    }


    @MyAnnotation("Hello")
    @MyAnnotation("World")
    public static void showTwo(@MyAnnotation("123") String num) {

    }
}

8、总结

就我在工作中的实际使用而言,java8中最有用的是stream流和新时间日期api。但时间日期api通常会在实际开发中被单独封装成一个util工具类,需要格式转换还是计算时间直接调用工具类中的相应方法就行了。唯一用的比较多的是stream api,stream api结合Lambda表达式可以极大的简化代码。常见的像filter、map、sort、limit等可以很灵活的处理list中的数据。尤其是在后端开发中会涉及调取很多第三方接口,用stream api处理第三方接口的数据会非常方便。对于一些查库操作,使用stream api可以很好的减少查库次数,降低数据库io。其实就是先多查一些数据,然后用stream api处理。可以避免一些循环查询的情况,提高程序执行效率。

9、参考资料 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金斗潼关

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值