JDK1.8超详细

idea 快捷键:

iter:for循环
itco:遍历集合的for循环


Lambda语法:

左边参数,右边Lambda体(功能)
左右遇一括号省——若Lambda体中只有一条语句,return和大括号{}都可以省略不写。
左侧推断类型省
能省则省


四大函数式接口

Consumer:消费型接口。有去无回。有一个输入参数,没有返回值。

Consumer<T>
 void accept(T t);

Supplier:供给型接口。没有输入参数,只有返回值。

Supplier<T>
    T get();

Funtion<T,R>:函数型接口。有一个输入参数,有返回值。

Function<T R>R apply(T t);

Predicate:断言型接口。有一个输入参数,返回值只能是布尔值。

Predicate<T>
boolean test(T t);

1、什么是Stream流?

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

【注意】:

①Stream 自己不会存储元素。
②Stream 不会改变源对象。只会返回一个持有结果的新的Stream
③Stream 操作是延迟执行的(懒加载)。意味着是会等到需要结果的时候才执行。

2、Stream操作的三个步骤

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

2、方法引用与构造器引用

1、方法引用
若Lambda体中的内容有方法已经实现了,我们就可以使用“方法引用”(可以理解为方法引用就是Lambda表达式的另外一种表现形式)

主要三种语法格式:
对象 ::实例方法名
类::静态方法名
类::实例方法名

【注意】:
1、Lambda体重调用方法的参数列表和返回值类型,要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
2、若Lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可使用类名::实例方法名

2.构造器引用
语法格式:类::new
【注意】:
需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致!

3、数组引用
语法格式:Type[]::new


2. 创建Stream流的四种方式:

@Test
public void test(){
    //1、通过Collection系列集合提供的stream()和parallelStream()来获取流
    List<String> list = new ArrayList<>();
    Stream<String> stream = list.stream();

    //2、通过Arrays中的静态方法stream()获取数组流
    Employee[] emps = new Employee[10];
    Stream<Employee> stream1 = Arrays.stream(emps);

    //3、通过Stream中的静态方法of()
    Stream<String> stream2 = Stream.of("aa", "bb", "cc");

    //4、创建无限流
    //1)迭代,Stream中的静态方法iterate()
    Stream<Integer> stream3 = Stream.iterate(0, x -> x + 2);
    stream3.limit(10).forEach(System.out::println);

    //2)生成,Stream中的静态方法generate()
    Stream<Double> stream4 = Stream.generate(() -> Math.random());
    stream4.limit(5).forEach(System.out::println);
}

4、筛选与切片(中间操作 )

filter:接收 Lambda ,从流中排除某些元素。filter里是Predicate断言型接口。
limit:截断流,使其元素不超过给定数量
skip(n):跳过元素。与 limit(n) 互补
distinct:筛选,通过流所生成的元素 hashCode() 与 equals() 取除重复元素

【注意】:只要没有执行终止操作,中间操作都不会执行

//内部迭代
    @Test
    public void test1(){
        employees.stream()
                 //中间操作:不会执行任何操作
                 .filter(e -> {
                     System.out.println("Stream API的中间操作");
                     return e.getAge()>35;
                 })
                 //终止操作:一次性执行全部内容,惰性求值
                 .forEach(System.out::println);
    }

//输出结果:
//Stream API的中间操作
//Employee(name=张三, age=36, salary=9999.99)
//Stream API的中间操作
//Stream API的中间操作 //Employee(name=王五, age=48, salary=6666.66) //Stream API的中间操作
//Employee(name=赵六, age=52, salary=3333.33) //Stream API的中间操作


内部迭代:迭代操作由Stream API完成

外部迭代:自己通过迭代器Iterator完成迭代操作

    //外部迭代
    @Test
    public void test2(){
        Iterator<Employee> it = employees.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }

//输出结果:
//Employee(name=张三, age=36, salary=9999.99)
//Employee(name=李四, age=30, salary=5555.55)
//Employee(name=王五, age=48, salary=6666.66)
//Employee(name=赵六, age=52, salary=3333.33)
//Employee(name=田七, age=8, salary=7777.77)


limit是短路的,即找到符合条件之后,就不再进行之后的迭代操作。

@Test
public void test3(){
    employees.stream()
             .filter(e ->{
                 System.out.println("短路!");
                 return e.getSalary()>5000;
             })
             .limit(2)
             .forEach(System.out::println);
}

输出结果:
//短路!
//Employee(name=张三, age=36, salary=9999.99)
//短路!
//Employee(name=李四, age=30, salary=5555.55)


skip

@Test
public void test4(){
    employees.stream()
             .filter(e-> e.getSalary()>5000)
             //跳过2个元素,与limit互补。
             .skip(2)
             .forEach(System.out::println);
}

输出结果:
//Employee(name=王五, age=48, salary=6666.66)
//Employee(name=田七, age=8, salary=7777.77)


distinct

    List<Employee> employees = Arrays.asList(
            new Employee("张三",36,9999.99),
            new Employee("李四",30,5555.55),
            new Employee("王五",48,6666.66),
            new Employee("赵六",52,3333.33),
            new Employee("田七",8,7777.77),
            new Employee("田七",8,7777.77),
            new Employee("田七",8,7777.77)
    );
@Test
public void test5(){
    employees.stream()
             .filter(e->e.getSalary()>5000)
             .skip(2)
             /去除重复的元素,但是根据HashCode()equals()进行去除。所以需要重写这两个方法*/
             .distinct()
             .forEach(System.out::println);
}

输出结果:
//Employee(name=王五, age=48, salary=6666.66)
//Employee(name=田七, age=8, salary=7777.77)


5、映射(中间操作 )

map:接收 Lambda ,将元素转换为其他形式或提取信息;接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
flatMap:接收一个函数作为参数,将流中每一个值都换成另一个流,然后把所有流重新连接成一个流

//区别:
   List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
        Stream<Stream<Character>> stream = list.stream()
                                                //{{a,a,a},{b,b,b},{c,c,c}...}
                                                .map(TestStreamAPI::filterCharacter);
//        stream.forEach(System.out::println);
        stream.forEach(sm ->{
            sm.forEach(System.out::println);
        });
        System.out.println("=========================");
        Stream<Character> stream1 = list.stream()
               								 //{a,a,a,b,b,b,c,c,c...}
								             .flatMap(TestStreamAPI::filterCharacter);
        stream1.forEach(System.out::println);

6、排序(中间操作 )

sorted():自然排序(Comparable)
sorted(Comparator c):定制排序(Comparator)

    @Test
    public void test9(){
        List<String> list = Arrays.asList("ccc","aaa","eee","bbb","ddd");
        list.stream()
                //自然排序,按照Comparable的规则排序
                .sorted()
                .forEach(System.out::println);

        System.out.println("============================");
        employees.stream()
                    //自定义排序
                    .sorted((e1,e2)->{
                        if (e1.getAge()==e2.getAge()){
                            return e1.getName().compareTo(e2.getName());
                        }else{
                            return Integer.compare(e1.getAge(),e2.getAge());
                        }
                    })
                    .forEach(System.out::println);
    }

//输出结果:
//aaa
//bbb
//ccc
//ddd
//eee
//============================
//Employee(name=田七, age=8, salary=7777.77)
//Employee(name=田七, age=8, salary=7777.77)
//Employee(name=田七, age=8, salary=7777.77)
//Employee(name=李四, age=30, salary=5555.55)
//Employee(name=张三, age=36, salary=9999.99)
//Employee(name=王五, age=48, salary=6666.66)
//Employee(name=赵六, age=52, salary=3333.33)


7、查询与匹配(终止操作)

allMatch:检查是否匹配所有元素
anyMatch:检查是否至少匹配一个元素
noneMatch:检查是否没有匹配所有元素
findFirst:返回第一个元素
findAny:返回当前流中的任意元素
count:返回流中元素的总个数
max:返回流中最大值
min:返回流中最小值

    List<Employee> employees = Arrays.asList(
            new Employee("张三",36,9999.99, Employee.Status.FREE),
            new Employee("李四",30,5555.55, Employee.Status.BUSY),
            new Employee("王五",48,6666.66, Employee.Status.VOCATION),
            new Employee("赵六",52,3333.33, Employee.Status.FREE),
            new Employee("田七",8,7777.77, Employee.Status.BUSY)
    );

    
    @Test
    public void test(){
        //allMatch:检查是否匹配所有元素
        boolean b = employees.stream()
                .allMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b);//输出结果:false
        
        //anyMatch:检查是否至少匹配一个元素
        boolean b1 = employees.stream()
                .anyMatch(e -> e.getStatus().equals(Employee.Status.FREE));
        System.out.println(b1);//输出结果:true
        
        //noneMatch:检查是否没有匹配所有元素。不是没有匹配的元素,双重否定=存在匹配的元素
        boolean b2 = employees.stream()
                .noneMatch(e -> e.getStatus().equals(Employee.Status.VOCATION));
        System.out.println(b2);//输出结果:false
        
        //findFirst:返回第一个元素。返回的是Optional容器对象,说明findFirst可能会报空指针错误。
        Optional<Employee> op = employees.stream()
                .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
                .findFirst();
        System.out.println(op.get());//输出结果:Employee(name=赵六, age=52, salary=3333.33, status=FREE)
        //若在Double前加上-,结果是最高工资的。
        
        //findAny:返回当前流中的任意元素。
        Optional<Employee> op1 = employees.stream()
                .filter(e -> e.getStatus().equals(Employee.Status.FREE))
                .findAny();
        System.out.println(op1.get());//输出结果:Employee(name=张三, age=36, salary=9999.99, status=FREE)    
    }
    
    
    @Test
    public void test1(){
        //count:返回流中元素的总个数
        long count = employees.stream()
                .count();
        System.out.println(count);//输出结果:5
        
        //需求:获取工资最高的员工信息
        //max:返回流中最大值。
        Optional<Employee> op = employees.stream()
                .max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(op.get());//输出结果:Employee(name=张三, age=36, salary=9999.99, status=FREE)
        
        //需求:获取最低员工的工资
        //min:返回流中最小值
        Optional<Double> minOp = employees.stream()
                .map(Employee::getSalary)
//                .min((e1, e2) -> Double.compare(e1, e2));
                .min(Double::compare);
        System.out.println(minOp.get());//输出结果:3333.33
        
    }

8、归约与收集(终止操作)

归约:reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以将流中的数据反复结合起来,得到一个值
收集:collect 将流转换成其他形式;接收一个 Collector 接口的实现,用于给流中元素做汇总的方法

reduce归约

    @Test
    public void test2(){
        List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer nums = integers.stream()
                .reduce(0, (x, y) -> x + y);
        System.out.println(nums);

        System.out.println("=====================");
        //需求:求出当前公司中所有员工的工资总和
        Optional<Double> total = employees.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);
        System.out.println(total.get());
    }
//输出结果:
//55
//=====================
//33333.3

map和reduce的连接通常称为map-reduce模式,因Google用它来进行网络搜索而出名


collect收集
Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map),但是Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例。

     List<Employee> employees = Arrays.asList(
            new Employee("张三",36,9999.99, Employee.Status.FREE),
            new Employee("李四",30,5555.55, Employee.Status.BUSY),
            new Employee("王五",48,6666.66, Employee.Status.VOCATION),
            new Employee("赵六",52,3333.33, Employee.Status.FREE),
            new Employee("田七",8,7777.77, Employee.Status.BUSY),
            new Employee("田七",8,7777.77, Employee.Status.BUSY)
    );

    @Test
    public void test3(){

        //需求:将公司中员工的所有名字提取收集起来放入到一个集合中
        //.collect(Collectors.toList())
        List<String> list = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        list.forEach(System.out::println);
        System.out.println("==============================");

        //.collect(Collectors.toSet())
        Set<String> set = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toSet());
        set.forEach(System.out::println);//元素不重复
        System.out.println("==============================");

        //放入到特殊集合中
        //.collect(Collectors.toCollection(HashSet::new))
        HashSet<String> hs = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(HashSet::new));
        hs.forEach(System.out::println);
    }
 @Test
    public void test4(){
        //收集元素总数
        Long nums = employees.stream()
                .collect(Collectors.counting());
        System.out.println(nums);
        System.out.println("=========================");

        //收集平均值
        Double avg = employees.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println(avg);
        System.out.println("=========================");

        //收集总和
        Double total = employees.stream()
                .collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println(total);
        System.out.println("=========================");

        //最大值
        Optional<Employee> max = employees.stream()
                .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        System.out.println(max.get());

        //最小值
        Optional<Double> min = employees.stream()
                .map(Employee::getSalary)
                .collect(Collectors.minBy(Double::compare));
        System.out.println(min.get());
    }
//输出结果:
//5
//=========================
//6666.660000000001
//=========================
//33333.3
//=========================
//Employee(name=张三, age=36, salary=9999.99, status=FREE)
//3333.33
    @Test
    public void test5(){
        //分组
        //Collectors.groupingBy
        Map<Employee.Status, List<Employee>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(map);

        //多级分组
        Map<Employee.Status, Map<String, List<Employee>>> map2 = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy(e -> {
                    if (e.getAge() <= 35) {
                        return "青年";
                    } else if (e.getAge() <= 50) {
                        return "中年";
                    } else {
                        return "老年";
                    }
                })));
        System.out.println(map2);

        //分区
        //Collectors.partitioningBy
        Map<Boolean, List<Employee>> map3 = employees.stream()
                .collect(Collectors.partitioningBy(e -> e.getSalary() > 8000));
        System.out.println(map3);

        //先获取汇总
        //Collectors.summarizing...
        DoubleSummaryStatistics dss = employees.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(dss.getAverage());
        System.out.println(dss.getCount());
        System.out.println(dss.getMax());
        System.out.println(dss.getMin());
        System.out.println(dss.getSum());

        //字符串连接
        //Collectors.joining
        String str = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(",", "(", ")"));
        System.out.println(str);//输出结果:(张三,李四,王五,赵六,田七)
    }

  1、给定一个数字列表,
        // 如何返回一个由每个数的平方构成的列表?给定[1,2,3,4,5],应该返回[1,4,9,16,25]
        int[] nums = new int[]{1,2,3,4,5};
        Arrays.stream(nums)
                .map(x->x * x)
                .forEach(System.out::println);
        System.out.println("===================");
        
 2、怎样用map和reduce方法数一数流中有多少个EmployeeOptional<Integer> op = employees.stream()
                .map(e -> 1)
                .reduce(Integer::sum);
        System.out.println(op.get());

public class TestTransaction {

    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 test(){
        //1)找出2011年发生的所有交易,并按交易额排序(从低到高)
        transactions.stream()
                        .filter(t->t.getYear()==2011)
                        .sorted((t1,t2)->Integer.compare(t1.getValue(),t2.getValue()))
                        .forEach(System.out::println);
        System.out.println("=========================");
        //2)交易员都在哪些不同的城市工作过?
        transactions.stream()
                        .map(t->t.getTrader().getCity())
                        .distinct()
                        .forEach(System.out::println);
        System.out.println("=========================");
        //3)查找所有来自剑桥的交易员,并按姓名排序。
        transactions.stream()
                        .filter(t->t.getTrader().getCity().equals("Cambridge"))
                        .map(Transaction::getTrader)
                        .distinct()
                        .sorted((t1,t2)->t1.getName().compareTo(t2.getName()))
                        .forEach(System.out::println);
        System.out.println("=========================");
        //4)返回所有交易员的姓名字符串,按字母顺序排序。
        //题目存在歧义
        //解法1:
        transactions.stream()
                        .map(t->t.getTrader().getName())
                        .sorted()
                        .forEach(System.out::println);
        System.out.println("==========================");
        //解法2:
        String str = transactions.stream()
                .map(t -> t.getTrader().getName())
                .sorted()
                .reduce("", String::concat);
        System.out.println(str);
        System.out.println("==========================");
        //解法3:
        transactions.stream()
                        .map(t->t.getTrader().getName())
                        .flatMap(TestTransaction::filterCharacter)
                        .sorted((s1,s2)->s1.compareToIgnoreCase(s2))
                        .forEach(System.out::print);
    }
    public static Stream<String> filterCharacter(String strs){
        List<String> list = new ArrayList<>();
        for (Character ch : strs.toCharArray()) {
            list.add(ch.toString());
        }
        return list.stream();
    }
}
//输出结果:
//Transaction{trader=Trader{name='Brian', city='Cambridge'}, year=2011, value=300}
//Transaction{trader=Trader{name='Raoul', city='Cambridge'}, year=2011, value=400}
//=========================
//Cambridge
//Milan
//=========================
//Trader{name='Alan', city='Cambridge'}
//Trader{name='Brian', city='Cambridge'}
//Trader{name='Raoul', city='Cambridge'}
//=========================
//Alan
//Brian
//Mario
//Mario
//Raoul
//Raoul
//==========================
//AlanBrianMarioMarioRaoulRaoul
//==========================
//aaaaaAaBiiilllMMnnoooorRRrruu

    @Test
    public void test2(){
        //5)有没有交易员是在米兰工作的?
        boolean b = transactions.stream()
                .anyMatch(t -> t.getTrader().getCity().equals("Milan"));
        System.out.println(b);
        System.out.println("==========================");
        //6)打印生活在剑桥的交易员的所有交易额
        Optional<Integer> sum = transactions.stream()
                .filter(t -> t.getTrader().getCity().equals("Cambridge"))
                .map(Transaction::getValue)
                .reduce(Integer::sum);
        System.out.println(sum.get());
        System.out.println("==========================");
        //7)所有交易中,最高的交易额是多少
        Optional<Integer> max = transactions.stream()
                .map(Transaction::getValue)
                .max(Integer::compareTo);
        System.out.println(max.get());
        System.out.println("==========================");
        //8)找到交易额最小的交易
        Optional<Transaction> min = transactions.stream()
                .min((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()));
        System.out.println(min.get());
    }
//输出结果:
//true
//==========================
//2650
//==========================
//1000
//==========================
//Transaction{trader=Trader{name='Brian', city='Cambridge'}, year=2011, value=300}

public class Test {
    public static void main(String[] args) {
        User u1 = new User(1,"a",21);
        User u2 = new User(2,"b",22);
        User u3 = new User(3,"c",23);
        User u4 = new User(4,"d",24);
        User u5 = new User(6,"e",25);
        // 集合就是存储
        List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
        //计算交给Stream
        //lambda表达式、链式编程、函数式接口、Stream流式计算
        list.stream()
                .filter(u->u.getId()%2==0)
                .filter(u->u.getAge()>23)
                .map(u->u.getName().toUpperCase())
                .sorted((uu1,uu2)->uu2.compareTo(uu1))
                .limit(1)
                .forEach(System.out::println);
    }
}

七、并行流与串行流

1、简述

public class TestStreamAPI2 {

    List<Employee> employees = Arrays.asList(
            new Employee("张三",36,9999.99, Employee.Status.FREE),
            new Employee("李四",30,5555.55, Employee.Status.BUSY),
            new Employee("王五",48,6666.66, Employee.Status.VOCATION),
            new Employee("赵六",52,3333.33, Employee.Status.FREE),
            new Employee("赵六",52,3333.33, Employee.Status.FREE),
            new Employee("赵六",52,3333.33, Employee.Status.FREE),
            new Employee("田七",8,7777.77, Employee.Status.BUSY)
    );

    @Test
    public void test(){
        //stream()创建的是串行流
        Optional<Employee> op1 = employees.stream()
                .filter(e -> e.getStatus().equals(Employee.Status.FREE))
                .findAny();
        System.out.println(op1.get());//输出结果:Employee(name=张三, age=36, salary=9999.99, status=FREE)
    }

    @Test
    public void test2(){
        //parallelStream()创建的是并行流
        Optional<Employee> op2 = employees.parallelStream()
                .filter(e -> e.getStatus().equals(Employee.Status.FREE))
                .findAny();
        System.out.println(op2.get());//输出结果:Employee(name=赵六, age=52, salary=3333.33, status=FREE)
    }
}

说明:在上述例子当中,stream()创建的串行流,它是顺序找符合条件的任意一个元素,所以它永远返回的会是张三这个员工;而parallelStream(),意味着是并行查找符号条件的任意一个元素,而此时赵六的元素要多一些,选到的概率相对较大一些,但结果仍是不确定性的。


2、ForkJoin

什么是ForkJoin?
ForkJoin是在JDK1.7出来的,作用是并行执行任务来提高效率。在大数据量下更适用!
思想:将大任务拆分成小任务执行,最后合并结果。
特点:双端队列,工作窃取机制。
但实际较少使用,因为实现起来比较复杂!其中的逻辑关系需要我们自己去编写!

RecursiveAction:递归事件,没有返回值
RecursiveTask:递归任务,有返回值

public class ForkJoinCalculate extends RecursiveTask<Long> {

    private static final long serialVersionUID = 1L;

    private long start;
    private long end;

    private static final long THRESHOLD = 10000L;

    public ForkJoinCalculate(long start, long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {

        long length = end - start;
        if (length <= THRESHOLD){
            //小于临界值,不需要ForkJoin,直接for循环
            long sum = 0L;
            for (long i = start; i <= end; i++) {
                sum += i;
            }
            return sum;
        }else {//大于临界值,进行ForkJoin
            //中间值
            long middle = (start + end)/2;
            ForkJoinCalculate left = new ForkJoinCalculate(start, middle);
            left.fork();//拆分任务,同时把任务压入线程队列
            ForkJoinCalculate right = new ForkJoinCalculate(middle + 1, end);
            right.fork();//拆分任务,同时把任务压入线程队列
            return left.join() + right.join();
        }
    }
}


3、普通for循环、ForkJoin、并行流运行对比

public class TestForkJoin {
    public static void main(String[] args) {
        test();//3282
        test1();//501
        test2();//471
    }

    /**
     * 普通for循环
     */
    public static void test(){
        long start = System.currentTimeMillis();
        long sum = 0;
        for (Long i = 0L; i <= 10_0000_0000L ; i++) {
            sum+=i;
        }
        long end = System.currentTimeMillis();
        System.out.println("sum=" + sum +"时间:"+ (end - start));
    }

    /**
     * 使用ForkJoin
     */
    public static void test1(){
        long start = System.currentTimeMillis();
        ForkJoinPool pool = new ForkJoinPool();
        ForkJoinCalculate task = new ForkJoinCalculate(0L, 10_0000_0000L);
        Long sum = pool.invoke(task);
        long end = System.currentTimeMillis();
        System.out.println("sum=" + sum +"时间:"+ (end - start));
    }

    /**
     * 使用并行流
     */
    public static void test2(){
        long start = System.currentTimeMillis();
        long sum = LongStream.rangeClosed(0, 10_0000_0000)
                .parallel()
                .reduce(Long::sum)
                .getAsLong();
        long end = System.currentTimeMillis();
        System.out.println("sum=" + sum +"时间:"+ (end - start));
    }
}

八、Optional容器类

定义:Optional 类 (java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在用 Optional 可以更好的表达这个概念;并且可以避免空指针异常

常用方法:

Optional.of(T t):创建一个 Optional 实例
Optional.empty(T t):创建一个空的 Optional 实例
Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则空实例
isPresent():判断是否包含某值
orElse(T t):如果调用对象包含值,返回该值,否则返回 t
orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回 s 获取的值
map(Function f):如果有值对其处理,并返回处理后的 Optional,否则返回 Optional.empty()
flatmap(Function mapper):与 map 相似,要求返回值必须是 Optional

使用测试:

public class TestOptional {

    @Test
    public void test(){
        //Optional.of(T t):创建一个 Optional 实例
        Optional<Employee> op = Optional.of(new Employee());
        Employee employee = op.get();
        System.out.println(employee);
    }

    @Test
    public void test1(){
        //Optional.empty(T t):创建一个空的 Optional 实例
        Optional<Object> op = Optional.empty();
        System.out.println(op.get());//java.util.NoSuchElementException: No value present
    }

    @Test
    public void test2(){
        //Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则空实例
        //ofNullable实质:return value == null ? empty() : of(value);
        Optional<Object> op = Optional.ofNullable(new Employee());
        System.out.println(op.get());
    }

    @Test
    public void test3(){
        //isPresent():判断是否包含某值
        Optional<Object> op = Optional.ofNullable(null);
        if (op.isPresent()){
            op.get();
        }
    }

    @Test
    public void test4(){
        //orElse(T t):如果调用对象包含值,返回该值,否则返回 t
        Optional<Object> op = Optional.ofNullable(null);
        Employee emp = (Employee) op.orElse(new Employee("纸飞机", 23, 8000.88, Employee.Status.FREE));
        System.out.println(emp);
    }

    @Test
    public void test5(){
        //orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回 s 获取的值
        Optional<Object> op = Optional.ofNullable(null);
        Employee emp = (Employee) op.orElseGet(() -> new Employee("纸飞机", 23, 8000.88, Employee.Status.FREE));
        System.out.println(emp);
    }

    @Test
    public void test6(){
        //map(Function f):如果有值对其处理,并返回处理后的 Optional,否则返回 Optional.empty()
        //flatmap(Function mapper):与 map 相似,要求返回值必须是 Optional
        //将容器中的对象应用到map中的函数上
        Optional<Employee> op = Optional.ofNullable(new Employee("纸飞机", 23, 8000.88, Employee.Status.FREE));
        Optional<String> str = op.map(e -> e.getName());
        Optional<Double> sal = op.flatMap(e -> Optional.of(e.getSalary()));
        System.out.println(str.get());
        System.out.println(sal.get());
    }
}

九、接口中的默认方法和静态方法

1、默认方法
Java 8中接口中允许有方法体的默认方法(default修饰)。

但思考问题:

一个类同时继承了一个类且实现了一个接口,而继承的父类和接口中存在相同的方法时,在通过这个类的实例调这个相同的方法时,会冲突吗?会执行的是哪个方法?

接口中的默认方法遵循类优先原则

若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时。

选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
接口冲突。如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突。

2、静态方法
Java 8 接口中允许有具体实现的静态方法。


十、新日期和时间

传统日期时间存在线程安全问题,即不是线程安全的。且比较不方便和混乱。

Java 8 的新日期和时间全部在java.time下这个包下,且不管怎么改变都会产生一个新的实例,即是线程安全的。

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

ISO-8601是国际标准化组织制定的现代公民的日期和时间的表示法。

@Test
    public void test(){
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);

        LocalDateTime ldt1 = LocalDateTime.of(2020, 10, 29, 8, 11, 10);
        System.out.println(ldt1);

        LocalDateTime ldt3 = ldt.plusYears(2);
        System.out.println(ldt3);

        LocalDateTime ldt4 = ldt.minusMonths(6);
        System.out.println(ldt4);

        System.out.println(ldt.getYear());
        System.out.println(ldt.getMonthValue());
        System.out.println(ldt.getDayOfMonth());
        System.out.println(ldt.getHour());
        System.out.println(ldt.getMinute());
        System.out.println(ldt.getSecond());
    }

//输出结果:
//2020-10-29T08:15:26.785
//2020-10-29T08:11:10
//2022-10-29T08:15:26.785
//2020-04-29T08:15:26.785
//2020
//10
//29
//8
//15
//26

2、Instant
Instant:时间戳(以Unix元年:1970年1月1日00:00:00到某个时间之间的毫秒数)

@Test
public void test1(){
    Instant ins = Instant.now();//默认是获取的UTC时区
    System.out.println(ins);

    OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));
    System.out.println(odt);

    System.out.println(ins.toEpochMilli());

    Instant ins1 = Instant.ofEpochSecond(60);
    System.out.println(ins1);
}

//输出结果:
//2020-10-29T00:24:04.286Z
//2020-10-29T08:24:04.286+08:00
//1603931044286
//1970-01-01T00:01:00Z

3、Duration、Period
Duration:计算两个“时间”之间的间隔

Period:计算两个“日期”之间的间隔

@Test
public void test3(){
    Instant ins = Instant.now();
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Instant ins1 = Instant.now();
    Duration duration = Duration.between(ins, ins1);
    System.out.println(duration.toMillis());
    System.out.println("=================================");

    LocalDateTime ldt = LocalDateTime.now();
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    LocalDateTime ldt1 = LocalDateTime.now();
    System.out.println(Duration.between(ldt, ldt1).toMillis());
}

//输出结果:
//1006
//=================================
//1016

@Test
public void test4(){
    LocalDate ld = LocalDate.of(2018, 4, 6);
    LocalDate ld1 = LocalDate.now();
    Period period = Period.between(ld, ld1);
    System.out.println(period);
    System.out.println(period.getYears());
    System.out.println(period.getMonths());
    System.out.println(period.getDays());
}

//输出结果:
//P2Y6M23D
//2
//6
//23

4、时间校正器
TemporalAdjuster:时间校正器。有时我们可能需要获取列入:将日期调整到“下个周日”等操作。

TemporalAdjustters:该类通过静态方法提供了 大量的常用TemporalAdjuster的实现。

 @Test
    public void test5(){
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);

        LocalDateTime ldt1 = ldt.withDayOfMonth(4);//指定具体为哪一天(号)
        System.out.println(ldt1);

        LocalDateTime ldt2 = ldt.with(TemporalAdjusters.next(DayOfWeek.SATURDAY));
        System.out.println(ldt2);

        //自定义时间校正器
        LocalDateTime ldt4 = ldt.with(l -> {
            LocalDateTime ldt3 = (LocalDateTime) l;
            DayOfWeek day = ldt3.getDayOfWeek();
            if (day.equals(DayOfWeek.FRIDAY)) {
                return ldt3.plusDays(3);
            } else if (day.equals(DayOfWeek.SATURDAY)) {
                return ldt3.plusDays(2);
            } else {
                return ldt3.plusDays(1);
            }
        });
        System.out.println(ldt4);
    }

//输出结果:
//2020-10-29T09:01:43.490
//2020-10-04T09:01:43.490
//2020-10-31T09:01:43.490
//2020-10-30T09:01:43.490

5、格式化日期/时间

 @Test
    public void test6(){
        DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
        LocalDateTime ldt = LocalDateTime.now();
        String strDate = ldt.format(dtf);
        System.out.println(strDate);

        System.out.println("=======================");
        DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
        String strDateTime = ldt.format(dtf1);
        System.out.println(strDateTime);

        LocalDateTime ldt1 = ldt.parse(strDateTime,dtf1);
        System.out.println(ldt1);
    }

//输出结果:
//2020-10-29
//=======================
//2020年10月29日 09:10:37
//2020-10-29T09:10:37

6、时区ZonedDate、ZonedTime、ZonedDateTime

  @Test
    public void test7(){
        Set<String> set = ZoneId.getAvailableZoneIds();
        set.forEach(System.out::println);
    }

    @Test
    public void test8(){
        LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));
        System.out.println(ldt);

        LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        ZonedDateTime zdt = ldt1.atZone(ZoneId.of("Asia/Shanghai"));
        System.out.println(zdt);//与UTC相比,有8小时时差
    }

//test8()输出结果:
//2020-10-29T03:21:40.219
//2020-10-29T09:21:40.235+08:00[Asia/Shanghai]

十一、重复注解和类型注解

Java8 对注解处理提供了两点改进:可重复注解以及可用于类型的注解。

@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String value() default "纸飞机";
}
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {

    MyAnnotation[] value();
}
/**
 * 重复注解和类型注解
 */
public class TestAnnotation {

    @MyAnnotation("Hello")
    @MyAnnotation("World")
    public void show(){

    }

    public void show2(@MyAnnotation String str){

    }

    /**
     * 配合反射使用
     */
    @Test
    public void test() throws Exception {
        Class<TestAnnotation> clazz = TestAnnotation.class;
        Method method = clazz.getMethod("show");
        MyAnnotation[] mas = method.getAnnotationsByType(MyAnnotation.class);
        for (MyAnnotation myAnnotation : mas) {
            System.out.println(myAnnotation.value());
        }
    }
}

//输出结果:
//Hello
//World

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值