前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDK8新特性

JDK8新特性

作者头像
星哥玩云
发布2022-09-14 20:32:13
1.2K0
发布2022-09-14 20:32:13
举报
文章被收录于专栏:开源部署开源部署

1、Lambda表达式

1.1、概述

首先,要想明白Lambda表达式就要先明白函数式接口,所以,咱们先来了解一下什么是函数式接口吧!

所谓函数式接口就是有且仅有一个抽象方法的接口

函数式接口就是适用于函数式编程场景的接口,java中的函数式编程的体现就是lambda!所以函数式接口 就是可以适用于Lambda使用的接口。

只有当接口中有且只有一个抽象方法的时候,Java中的lambda表达式才能顺利推导!

也就是说在Java中使用Lambda表达式必须符合函数式接口的规范

所以,使用Lambda接口的前提是:

(1)Lambda关联的接收对象必须是函数式接口。(也就是说方法的形参必须是接口)

(2)这个接口只能有一个抽象方法(函数式接口的规范)

1.2、函数式接口

代码语言:javascript
复制
/*
* 函数式接口:有且只有一个抽象方法!
* @FunctionalInterface:用来检测该接口中是否是只有一个抽象方法,如果不止一个就报错!
* */
@FunctionalInterface
public interface FunctionInter {
    public void method();
}

1.3、Lambda表达式和匿名内部类

Lambda表达式“本质上”是一个匿名内部类,只是二者体现形式不一样,但可以把Lambda表达式当做匿名内部类来理解!

1.3.1、匿名内部类

匿名内部类就是某个实现了接口的子类对象

不用匿名内部类

代码语言:javascript
复制
//未用匿名内部类
public class MyComparator implements Comparator<Integer> {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1-o2;
    }
}
代码语言:javascript
复制
public static void main(String[] args) {
     Comparator c = new MyComparator();//实现比较器接口,创建对象
     TreeSet<Integer> set = new TreeSet<Integer>(c);
    	
}

使用匿名内部类

代码语言:javascript
复制
public static void main(String[] args) {
        Comparator c = new MyComparator();//实现比较器接口,创建对象
        TreeSet<Integer> set = new TreeSet<Integer>(c);

    	//使用匿名内部类
        Comparator c2 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1-o2;
            }
        };//匿名内部类实现比较器接口
        TreeSet<Integer> set2 = new TreeSet<Integer>(c2);
}

1.3.2、Lambda表达式

代码语言:javascript
复制
//超简洁
TreeSet<Integer> set3 = new TreeSet<Integer>((o1,o2) ->o1-o2);
image20191223154231791.png
image20191223154231791.png

从上面的代码对比中,大家可以发现,lambda表达式真的超简洁!

1.4、Lambda表达式详解

1.4.1、Lambda表达式的标准写法

代码语言:javascript
复制
//可以没有形参,如果有多个形参,那么用“,”隔开
//方法体和形参之间用“->”连接
(参数类型 形参1,参数类型 形参2)->{ 
	方法体;
}

代码演示一(无参无返回值)

代码语言:javascript
复制
public interface FlyAble {
    public void fly();
}
代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        //匿名内部类的写法
        rocket(new FlyAble() {
            @Override
            public void fly() {
                System.out.println("i can fly!--匿名内部类");
            }
        });
        //lambda表达式的写法
        rocket(()->{
            System.out.println("i can fly!--Lambda表达式");
        });
    }

    public static void rocket(FlyAble f){
        f.fly();
    }
}

lambda表达式的本质就是重写接口中的方法

代码演示一(有参有返回值)

代码语言:javascript
复制
public interface FlyAble {
    public int fly(String demo2);
}
代码语言:javascript
复制
	public static void main(String[] args) {
        //匿名内部类的写法
        rocket(new FlyAble() {
            @Override
            public int fly(String name) {

                System.out.println("i can fly!--匿名内部类");

                return 30;//分行高度
            }
        },"小鸟");
        //lambda表达式的写法
        rocket((String name)->{
            System.out.println("i can fly!--Lambda表达式");
            return 10000;
        },"飞机");
    }

    public static void rocket(FlyAble f,String name){
        int height = f.fly(name);
        System.out.println(name+"的分行高度是:"+height);
    }
image20191225101215001.png
image20191225101215001.png

1.4.2、Lambda表达式的省略写法

(1)小括号内参数的类型可以省略

(2)如果小括号内有且仅有一个参数,则小括号可以省略

(3)如果大括号内有且仅有一个语句,可以同时省略大括号、return关键字及语句分号

例如:

代码语言:javascript
复制
public interface FlyAble {
    public void fly(String name);
}
代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        
     //lambda表达式的写法
     rocket(name->System.out.println(name+"can fly!--Lambda表达式"));
    }

    public static void rocket(FlyAble f){
        f.fly("bird");
    }
}
image20191223171055120.png
image20191223171055120.png

2、JDK8接口的方法增强

2.1、概述

JDK1.8之前,接口中允许出现的成员有静态常量、抽象方法

代码语言:javascript
复制
//JDK1.8以前
public interface InterA {
    //静态常量
    //抽象方法
}

JDK1.8之前只允许接口中出现抽象方法,但是在实际的使用过程中,发现这样会影响接口的扩展性。例如:当往一个接口中添加新的抽象方法时,原来实现该接口的类都会报错!这样就显得“牵一发而动全身”!

image20191224143119319.png
image20191224143119319.png

为了解决这一弊端,JDK在1.8版本中,对接口的功能进行了扩展!

JDK1.8之后,接口中允许出现的成员有静态常量、抽象方法、默认方法、静态方法

代码语言:javascript
复制
//JDK1.8以后
public interface InterB {
    //静态常量
    //抽象方法
    //默认方法
    //静态方法
}

2.2、JDK1.8接口新增方法种类

  • 默认方法
  • 静态方法

2.3、默认方法的定义和使用

2.3.1、默认方法的定义

默认方法定义在接口中

他是个有方法体的方法

他定义的关键字是default

default出现的位置在方法返回值类型前面

定义格式如下:

代码语言:javascript
复制
interface InterA {
    public void methodA();
    //默认方法
    public default void methodDef(){
        //功能代码
    }
}

2.3.2、默认方法的使用

(1)直接用

(2)重写

代码语言:javascript
复制
interface InterA {
    public void methodA();
    public default void methodDef(){
        System.out.println("default ... method");
    }
}

//直接用
class A implements InterA{
    @Override
    public void methodA() {

    }
}
//重写
class B implements InterA{
    @Override
    public void methodA() {

    }

    @Override
    public void methodDef() {
        System.out.println("B ...default ... method");
    }
}

class Test{
    public static void main(String[] args) {
        InterA a = new A();
        a.methodDef();//直接用

        InterA b = new B();
        b.methodDef();//重写
    }
}

运行结果:

image20191224144944826.png
image20191224144944826.png

2.4、静态方法的定义和使用

2.4.1、静态方法的定义

静态方法定义在接口中

他是个有方法体的静态方法

定义格式如下:

代码语言:javascript
复制
interface InterD {
    //定义静态方法
    public static void methodSta(){
        //方法体
    }
    public void methodA();
    public default void methodDef(){
        System.out.println("default ... method");
    }
}

从上面可以看出,接口中静态方法的定义和普通类中的静态方法的定义没啥区别!

2.4.2、静态方法的使用
image20191224150525522.png
image20191224150525522.png

注意:接口中的静态方法只能通过接口名调用

2.5、接口中静态方法和默认方法的区别

1、默认方法通过实例调用,静态方法通过接口名调用

2、默认方法可以被继承,可以被重写

3、静态方法不能被继承,不能被重写,只能使用接口名调用静态方法

3、JDK提供的常用内置函数式接口

3.1、为什么JDK要提供这些常用内置函数接口?

因为Lambda表达式不关心接口名称,只关心接口的形参列表及返回值,所以为了方便我们使用Lambda表达式进行编程(函数式编程),JDK就提供了大量形参列表不同,返回值不同的函数式接口!

3.2、常用的函数式接口如下

(1)Supplier接口:供给型接口

(2)Consumer接口:消费型接口

(3)Function接口:转换型接口

(4)Predicate接口:判断型接口

3.2.1、Supplier接口:供给型接口
代码语言:javascript
复制
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

Supplier接口,他可以完成供给的功能,对应的lambda表达式需要“对外提供”一个符合泛型类型的对象数据。

供给型接口:通过get方法得到一个返回值,该返回值类型,通过泛型规定,是一个无参有返回值的接口!

案例:使用Lambda表达式返回数组元素的最小值!

代码语言:javascript
复制
    public static void main(String[] args) {
        printMin(()->{
            int[] arr = {1,2,3,4,5};
            Arrays.sort(arr);
            return arr[0];
        });
    }

    public static void printMin(Supplier<Integer> min){
        Integer minVlaue = min.get();
        System.out.println(minVlaue);
    }
3.2.2、Consumer接口:消费型接口
代码语言:javascript
复制
@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);
}

案例:把一个字符串中的字母全部转换成小写

代码语言:javascript
复制
	public static void main(String[] args) {
        toLower((String str)->{
            String lower = str.toLowerCase();
            System.out.println(lower);
        });
    }

    public static void toLower(Consumer<String> consumer){
        consumer.accept("HelloWorld");
    }

案例:把一个字符串既转换成大小,又转换成小写

代码语言:javascript
复制
	public static void main(String[] args) {
        toLowerAndToUpper((String str)->{
            System.out.println(str.toLowerCase());
        },
        (String str)->{
            System.out.println(str.toUpperCase());
        });
    }

    public static void toLowerAndToUpper(Consumer<String> consumer1,Consumer<String> consumer2){
        consumer1.accept("HelloWorld");
        consumer2.accept("HelloWorld");
    }

另一种写法

代码语言:javascript
复制
public static void main(String[] args) {
        toLowerAndToUpper((String str)->{
            System.out.println(str.toLowerCase());
        },
        (String str)->{
            System.out.println(str.toUpperCase());
        });
    }

    public static void toLowerAndToUpper(Consumer<String> consumer1,Consumer<String> consumer2){
        consumer1.andThan(consumer2).accept("HelloWorld");
    }
image20191224164102167.png
image20191224164102167.png
3.2.3、Function接口:转换型接口
代码语言:javascript
复制
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

案例:把字符串转换成一个整数并返回

代码语言:javascript
复制
	public static void main(String[] args) {
        parseToInt((String str)->{
            return Integer.parseInt(str);
        });
    }
    public static void parseToInt(Function<String,Integer> fun){
        Integer apply = fun.apply("10");
        System.out.println(apply);
    }

案例:把两个字符串转换成整数,并对这两个整数求和

代码语言:javascript
复制
	public static void main(String[] args) {
        sum((String str)->{
            return Integer.parseInt(str);
        },(String str)->{
            return Integer.parseInt(str);
        });
    }
    public static void sum(Function<String,Integer> 					fun1,Function<String,Integer> fun2){
        Integer num1 = fun1.apply("10");
        Integer num2 = fun1.apply("10");
        System.out.println(num1+num2);
    }

案例:传递两个参数,第一个参数是个字符串,要求把这个字符串转成数字;第二个是要求把转换之后的数字乘以5

代码语言:javascript
复制
	public static void main(String[] args) {
        mul((String str)->{
            return Integer.parseInt(str);
        },(Integer i)->{
            return i*5;
        });
    }

    public static void mul(Function<String,Integer> fun1,Function<Integer,Integer> fun2){
        Integer num1 = fun1.apply("10");
        Integer num2 = fun2.apply(num1);
        System.out.println(num2);
    }

另外的实现方式

代码语言:javascript
复制
public static void main(String[] args) {
        mul((String str)->{
            return Integer.parseInt(str);
        },(Integer i)->{
            return i*5;
        });
    }


    public static void mul(Function<String,Integer> fun1,Function<Integer,Integer> fun2){
        fun1.andThen(fun2).apply("10");
    }
image20191224194531786.png
image20191224194531786.png
3.2.4、Predicate接口:判断型接口
代码语言:javascript
复制
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

案例:判断字符串的长度是否大于3

代码语言:javascript
复制
	public static void main(String[] args) {
        is3Length((String str)->{
            return str.length()>3;
        });
    }
    public static void is3Length(Predicate<String> pre){
        boolean fbb = pre.test("fbbb");
        System.out.println("长度是否是3个长度:"+fbb);

    }

案例:判断字符串中是否既包含W,也包含H

代码语言:javascript
复制
	public static void main(String[] args) {
        wANDh((String str)->{
            return str.contains("w") && str.contains("h");
        });
    }
    public static void wANDh(Predicate<String> pre){
        boolean rst = pre.test("wwaaah");
        System.out.println("是否既包含W也包含H:"+rst);
    }

另外一种写法

代码语言:javascript
复制
public static void main(String[] args) {
        wANDh((String str)->{
            return str.contains("w");
        },(String str)->{
            return str.contains("h");
        });
    }
    public static void wANDh(Predicate<String> pre1,Predicate<String> pre2){
        boolean rst1 = pre1.test("hahwahah");
        boolean rst2 = pre2.test("hahwahah");
        boolean rst=rst1&&rst2;
        System.out.println("是否既包含W也包含H:"+rst);
    }

另外一种写法

代码语言:javascript
复制
	public static void main(String[] args) {
        wANDh((String str)->{
            return str.contains("w");
        },(String str)->{
            return str.contains("h");
        });
    }

    public static void wANDh(Predicate<String> pre1,Predicate<String> pre2){
        boolean rst = pre1.and(pre2).test("aaahhaaawww");
        System.out.println("是否既包含W也包含H:"+rst);
    }
image20191224222921968.png
image20191224222921968.png

案例:使用Lambda表达式判断一个字符串中包含W或者包含H

代码语言:javascript
复制
	public static void main(String[] args) {
       wORh((String str)->{
           return str.contains("w");
       },(String str)->{
           return str.contains("h");
       });
    }

    public static void wORh(Predicate<String> pre1,Predicate<String> pre2){
        boolean rst = pre1.or(pre2).test("aaahhaaawww");
        System.out.println("是否包含W或包含H:"+rst);
    }
image20191224223510283.png
image20191224223510283.png

案例:使用Lambda表达式判断一个字符串中是否不包含W

代码语言:javascript
复制
	public static void main(String[] args) {
        isNotContain((String str)->{
            return str.contains("a");
        });
    }

    public static void isNotContain(Predicate<String> pre1){
        boolean rst = pre1.negate().test("hahwahah");
        System.out.println("是否不包含:"+rst);
    }

negate()的作用就是对后面的test方法的结果取反。

4、Lambda表达式的方法引用

定义:把方法中的代码像变量值一样传递 (int a=10;int b=a)

把方法传递给抽象方法

4.1、Lambda表达式的方法引用的作用是什么?

先来看一下Lambda表达式中代码冗余的场景

代码语言:javascript
复制
public class DemoReferenceMethod {
	public static void main(String[] args) {
        int[] arr = {1,2,3};
        printSum(arr);//普通方法调用
       
        //lambda方法调用
        printSumLambda((Integer[] arr2)->{
           	int sum=0;
            for (int i : arr2) {
                sum+=i;
            }
            System.out.println(sum);
     	});
    }

    public static void printSum(int[] arr){
        int sum=0;
        for (int i : arr) {
            sum+=i;
        }
        System.out.println(sum);
    }

    public static void printSumLambda(Consumer<int[]> con){
        int[] arr = {1,2,3};
        con.accept(arr);
    }
}

从上面代码中中可以看出,printSum的方法内容和printSumLambda方法的lambda表达式的形参内容是一样的,所以这里存在了代码冗余。

​ printSum的方法内容=printSumLambda方法的lambda表达式

将上面的内容用方法引用改进

代码语言:javascript
复制
		//lambda方法调用
        printSumLambda((Integer[] arr2)->{
           	int sum=0;
            for (int i : arr2) {
                sum+=i;
            }
            System.out.println(sum);
     	});
     	//用方法引用改进上面的lambda表达式
     	printSumLambda(DemoReferenceMethod::printSum)

4.2、方法引用的格式

符号表示: ::

符号解释:双冒号为方法引用运算符,而它所在的表达式被称为方法引用。

应用场景:如果Lambda所有实现的方案,已经有其他方法存在相同方案,那么则可以使用方法引用。

4.3、常见引用方式

对象::方法名

类名::静态方法名

类名::方法名

类名::new (调用的构造器)

数组类型::new (调用数组的构造器)

4.3.1、对象::方法名
代码语言:javascript
复制
	public static void main(String[] args) {
        Date d = new Date();
        //不使用方法引用
        printTime(()->{
            return d.getTime();
        });

        //使用方法引用
        printTime(d::getTime);
    }
    public static void printTime(Supplier<Long> supp){
        Long aLong = supp.get();
        System.out.println(aLong);
    }
代码语言:javascript
复制
	public void test(){
		Date d = new Date();
		Supplier<Long> aLong= d::getTime;
		Long l=aLong.get();
		System.out.println(l);
	}

方法引用的注意事项:

​ A:被引用的方法,参数要和接口中抽象方法的参数一样

​ B:当接口抽象方法有返回值时,被引用的方法也必须有返回值

4.3.2、类名::静态方法名
代码语言:javascript
复制
	public void test(){
		Supplier<Long> aLong= ()->{
            return System.currentTimeMillis();
        };
        System.out.println(aLong.get());
		Supplier<Long> aLong2= System::currentTimeMillis;
        System.out.println(aLong2.get());
	}
4.3.3、类名::方法名
代码语言:javascript
复制
	public void test(){
		Function<String,Integer> fun1 = (String str)->{
            return str.length();
        }
        System.out.println(fun1.apply("hello"));
        //方法引用
        Function<String,Integer> fun2 = String::length;
        System.out.println(fun2.apply("helloabc"));
        //方法引用
        BiFunction(String,Integer,String) fun3 = String:substring;
        String sub=fun3.apply("hello",2);
        System.out.println(sub);
	}
4.3.4、类名::new (引用构造器)
代码语言:javascript
复制
class Person{
	public Person(){}
	public Person(String name,int age){
		this.name=name;
		this.age=age;
	}
	private String name;
	private int age;
	public String getName(){
		return name;
	}
	public void setName(String name){
		this.name=name;
	}
	public void setAge(int age){
		this.age=age;
	}
	public int getAge(){
		return age;
	}
}
代码语言:javascript
复制
	public void test(){
		Supplier<Person> sup = ()->{
            return new Person();
        }
        Person p = sup.get();
        //方法引用
        Supplier<Person> sup2 = Person::new;
        Person p2 = sup2.get();
        
        //方法引用
        BiFunction(String,Integer,Person) fun3 = Person:new;
        Person p3=fun3.apply("zs",2);
	}
4.3.5、数组类型::new
代码语言:javascript
复制
public void test{
	Function<String[],Integer> fun = (len)->{
        return new String[len];
    }
    String[] strs1 = fun.apply(10);
    
   	Function<String[],Integer> fun2 = String[]::new
    String[] strs2 = fun2.apply(10);
}

4.4、方法引用总结

方法引用是对Lambda表达式符合特定情况下的一种缩写,它使得我们的Lambda表达式更加的精简,也可以理解为Lambda表达式的缩写形式,不过要注意的是方法引用只能引用已经存在的方法!

5、Stream流

5.1、Stream流思想概述

Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序把一个原材料加工成一个商品。

通过使用Stream的API,能让我们快速完成许多复杂的操作,如筛选、切片、映射、查找、去除重复,统计,匹配和归纳。

5.2、Stream流思想的体现案例

代码语言:javascript
复制
/*
	假设集合中有如下人物:张学友,周润发,赵薇,张绍忠,张三丰。
	要求:1、拿到所有姓张的人物
		 2、拿到名字长度为3个字的
		 3、打印这些数据
	实现:
		传统做法:遍历三次集合,实现规定的要求
		流式做法:遍历一个,实现规定要求
*/
//1、传统做法
public class StreamDemo{
    public static void main(String[] args){
        ArrayList<String> list = new ArrayList<String>();
        Collections.addAll(list,"张无忌","周芷若","赵薇","张强","张三丰");
        
        //1、拿到所有姓张的人物
        ArrayList<String> zhang = new ArrayList<String>();
        for(String name:list){
            if(name.startsWith("张")){
                zhang.add(name);
            }
        }
        //2、拿到名字长度为3个字的
        ArrayList<String> threeLength = new ArrayList<String>();
        for(String name:zhang){
            if(name.length()==3){
                threeLength.add(name);
            }
        }
        //3、打印这些数据
        for(String name:threeLength){
            System.out.println(name);
        }
    }
}
代码语言:javascript
复制
//2、流式做法
public class StreamDemo2{
    public static void main(String[] args){
        ArrayList<String> list = new ArrayList<String>();
        Collections.addAll(list,"张无忌","周芷若","赵薇","张强","张三丰");
        list.stream().filter(s->s.startsWith("张")).
            filter(s->s.length()==3).
            forEach(System.out::println);
    }
}

打印结果:

image20191226223540709.png
image20191226223540709.png

5.3、获取Stream流的两种方式

(1)根据Collection获取流

(2)Stream中的静态方法of获取流

5.3.1、根据Collection的stream()方法获取流
image20191226224852262.png
image20191226224852262.png
5.3.2、根据Stream类的静态of()方法
image20191226231338356.png
image20191226231338356.png

直接传入多个字符串

image20191226230915393.png
image20191226230915393.png

传入一个字符串数组

image20191226231234495.png
image20191226231234495.png

传入一个整数数组

image20191226231749246.png
image20191226231749246.png

5.5、Stream的注意事项

​ 1、Stream只能操作一次

​ 2、Stream方法返回的是新的流

​ 3、Stream不调用终结方法,终结的操作不会执行

image20191226233055160.png
image20191226233055160.png

5.4、Stream常用API

image20191226231955153.png
image20191226231955153.png

Stream的API分为两类:

​ 1、终结方法—>返回值不是Stream类型—>不支持链式调用

​ 2、非终结方法—>返回值是Stream类型—>支持链式调用

注意:concat是Stream的静态方法

5.6、Stream常用API演示

forEach:逐个遍历

image20191228112330032.png
image20191228112330032.png

count:逐个遍历

image20191228112514406.png
image20191228112514406.png

limit:显示前几个

image20191226233524336.png
image20191226233524336.png

skip:跳过前几个

image20191226233710848.png
image20191226233710848.png

map:就是把一种类型的流映射成另外一种流

这里的map和集合中的map不是一个意思,这里的map只是把一种类型的值映射成另外一种类型的值,没有键值对!

把字符串转换成整数

image20191227091942113.png
image20191227091942113.png

sorted:对流中的数据进行排序

image20191227093053933.png
image20191227093053933.png

distinced:对流中的数据进行去重

image20191227094003626.png
image20191227094003626.png

math:元素匹配,有三种匹配情况

(1)allMatch():匹配所有

image20191227101047230.png
image20191227101047230.png

(2)noneMatch():判断是否是无匹配

image20191227101407973.png
image20191227101407973.png

(3)anyMatch():只要有一个匹配就行

image20191227101648684.png
image20191227101648684.png

find:元素查找

查找第一个:

方式一:findFirst()

image20191227102116763.png
image20191227102116763.png

方式二:findAny()

image20191227102736429.png
image20191227102736429.png

max和min方法,查找最大值和最小值

image20191227103408901.png
image20191227103408901.png

reduce:对数据进行加工处理

(1)对数据进行求和

image20191227105940811.png
image20191227105940811.png
image20191227110149167.png
image20191227110149167.png

(2)找最大值

image20191227110413811.png
image20191227110413811.png

map和reduce结合的练习

(1)求集合中Person对象的年龄总和

代码语言:javascript
复制
 public static void main(String[] args) {
     //求流中的人的年龄和
     ArrayList<Person> list = new ArrayList<Person>();
     Collections.addAll(list,new Person("张学友",18),
     new Person("周杰伦",19),
     new Person("周润发",20),
     new Person("张学友",40));
     Integer totalAge = list.stream().map((p) -> {
     return p.getAge();
     }).reduce(0, (x, y) -> {
     return x + y;
     });
     System.out.println(totalAge);
  }
image20191228165443504.png
image20191228165443504.png

(2)求Person中年龄最大是多少

代码语言:javascript
复制
	public static void main(String[] args) {
        //求流中的人的最大年龄
        ArrayList<Person> list = new ArrayList<Person>();
        Collections.addAll(list,new Person("张学友",18),
                new Person("周杰伦",19),
                new Person("周润发",20),
                new Person("张学友",40));
        Integer max = list.stream().map((p) -> p.getAge()).reduce(0, Integer::max);
        System.out.println(max);
    }

(3)求字符串数组中”a“出现了多少次?

代码语言:javascript
复制
	public static void main(String[] args) {
        //求字符串数组中“a”出现了多少次
        String[] str = {"a","b","c","a","b"};
        Integer count = Stream.of(str).map((s) -> {
            if (s == "a") {
                return 1;
            } else {
                return 0;
            }
        }).reduce(0, (x, y) -> {
            return x + y;
        });
        System.out.println(count);
    }
image20191228171603967.png
image20191228171603967.png

Stream流的mapToInt方法

如果需要将Stream中的Integer类型数据转换成int类型,可以使用mapToInt方法。

image20191229204107906.png
image20191229204107906.png

InteStream和Stream的继承体系

image20191229210122426.png
image20191229210122426.png

mapToInt的基本用法

代码语言:javascript
复制
public static void main(String[] args) {
        IntStream intStream = Stream.of(1, 2, 3).mapToInt((i)->i.intValue());
        intStream.forEach(System.out::println);
    }

使用基本数据类型可以节省内存空间

image20191229211033176.png
image20191229211033176.png

收集Stream流的结果

(1)收集流的结果到集合中去

(2)收集流的结果到数组中去

收集流的结果到集合中去

public static Collector<T,?,List> toList():转换为List集合

public static Collector<T,?,Set> toSet():转换为List集合

public static <T, C extends Collection>Collector<T, ?, C> toCollection(Supplier collectionFactory):转换为指定集合

image20191230173604413.png
image20191230173604413.png
image20191230173803747.png
image20191230173803747.png
image20191230173410436.png
image20191230173410436.png

收集结果到数组中去

image20191230174101361.png
image20191230174101361.png
image20191230174308330.png
image20191230174308330.png

对流中的数据进行聚合计算

(1)获取最大值

(2)获取最小值

(3)求总和

(4)求平均值

(5)分组

(6)多级分组

(7)分区

(8)拼接

获取最大值

求四大天王中年龄最大的

image20191230175836562.png
image20191230175836562.png

求四大天王中年龄最小的

image20191230180206353.png
image20191230180206353.png

求四大天王的年龄总和

image20191230180939667.png
image20191230180939667.png

求四大天王的平均年龄

image20191230181225322.png
image20191230181225322.png

对流中的数据进行分组

四大天王按照年龄进行分组

image20191230202724654.png
image20191230202724654.png

map的便捷遍历方式

image20191230203939935.png
image20191230203939935.png

原理:

image20191230204019979.png
image20191230204019979.png
image20191230204106461.png
image20191230204106461.png

将年龄19岁以上(包括19)分为一组,19岁以下分为一组。

image20191230204953753.png
image20191230204953753.png
image20191230205019565.png
image20191230205019565.png

多级分组

先按性别进行分组,再按年龄进行分组

image20191230213347869.png
image20191230213347869.png
image20191230213406807.png
image20191230213406807.png

对流中的数据进行分区,true为一个列表区,false为一个列表区

image20191230214934916.png
image20191230214934916.png

对流中的数据进行拼接

image20191230222348255.png
image20191230222348255.png
image20191230222410033.png
image20191230222410033.png

6、并行的Stream流

串行的Stream流

image20191230225844732.png
image20191230225844732.png

这样单线程处理,如果数量大,cpu核心多,势必会造成效率低下、资源浪费的情况!

6.1、并行的Stream流的获取方式

(1)通过集合直接获取并行流

(2)通过Stream对象的parallel()方法将串行流转变成并行流

方式一:通过集合直接获取并行流

image20191230231325206.png
image20191230231325206.png

方式二:通过Stream对象的parallel()方法将串行流转变成并行流

image20191230232040141.png
image20191230232040141.png

并行的Stream流和串行的Stream流的计算效率对比

需求:计算8亿的累加和

(1)for循环

image20191230233854538.png
image20191230233854538.png

(2)串行流

image20191231101905444.png
image20191231101905444.png

(3)并行流

image20191231101716330.png
image20191231101716330.png

6.2、并行流的线程安全问题

线程安全问题现场

需求:把1000个数字用并行流存到集合中去。

image20191231113610997.png
image20191231113610997.png

线程安全问题的解决方案:

(1)加锁

image20191231114953682.png
image20191231114953682.png

(2)使用线程安全的集合

image20191231115422463.png
image20191231115422463.png
image20191231120044278.png
image20191231120044278.png

(3)使用串行流

image20191231120857567.png
image20191231120857567.png

把并行流转成串行流

(4)使用Collectors的toList方法/Stream的toArray方法

image20191231135448301.png
image20191231135448301.png

7、Fork/Join框架

Fork/Join框架是并行流parallelStream底层使用的技术,Fork/Join框架是JDK1.7底层使用的技术。Fork/Join框架可以将一个大任务拆分成很多个小任务来异步执行。

Fork/Join框架主要包含三个模块:

(1):线程池,ForkJoinPool

(2):任务对象,ForkJoinTask

(3):执行任务的线程,ForkJoinWorkerThread

7.1、Fork/Join框架原理-分治法

ForkJoinPool主要用来使用分治法(Divide-and-Conquer Algorithm)来解决问题。典型的应用比如快速排序算法,ForkJoinPool需要使用相对少的线程来处理大量的任务。比如要对1000万个数据进行排序,那么会将这个任务分割成两个500万数据的合并任务和一个针对这两组500万数据的合并任务。以此类推,对于500万的数据也会做出同样的分割处理,到最后会设置一个阈值来规定当数据规模到多少时,停止这样的分割处理。比如,当元素的数量小于10时,会停止分割,转而使用插入排序对它们进行排序。那么到最后,所有的任务加起来会有大概2000000+个。问题的关键在于,对于一个任务而言,只有当它所有的子任务完成之后,它才能够被执行(其实就是采用了递归算法)。

image20191231142324818.png
image20191231142324818.png

7.2、Fork/Join原理-工作窃取法

当执行新的任务时Fork/Join框架会将任务拆分分成更小的任务执行,并将小任务加到线程队列中,当多个线程同时执行时,就总会有线程先执行完毕,有线程后执行完毕。先执行完毕的线程会从其它线程队列的末尾窃取任务来执行。为什么会从其它线程的末尾窃取了,因为如果从头部位置开始窃取,可能会遇到线程安全的问题。

7.3、ForkJoin案例

需求:使用Fork/Join计算1-10000的累加和,当一个任务的计算量大于3000时拆分任务,数量小于3000时计算。

image20191231143800285.png
image20191231143800285.png
代码语言:javascript
复制
package Test;

import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Demo10 {
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        ForkJoinPool pool = new ForkJoinPool();
        SumRecursiveTask task = new SumRecursiveTask(1L,10000L);
        Long rst = pool.invoke(task);
        long endTime = System.currentTimeMillis();
        System.out.println("结果是:"+rst);
        System.out.println("计算时间是:"+(endTime-startTime));

    }
}

class SumRecursiveTask extends RecursiveTask<Long>{
    private Long start;
    private Long end;
    private static final int THRESHOLD=3000;

    public SumRecursiveTask(Long start, Long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        Long length = end-start;//计算任务长度
        if(length<=THRESHOLD){//如果在阈值范围内就进行计算
            long sum=0;
            for(long i=start;i<=end;i++){
                sum+=i;
            }
            System.out.println("计算:start:"+start+"->"+end+"之间的值是:"+sum);
            return sum;
        }else{//如果不在阈值范围内就继续拆分
            long middle = (start+end)/2;
            System.out.println("拆分:左边"+start+"->"+middle+"  右边:"+(middle+1)+"->"+end);
            //递归调用
            SumRecursiveTask left = new SumRecursiveTask(start,middle);
            left.fork();
            SumRecursiveTask right = new SumRecursiveTask(middle+1,end);
            right.fork();
            return left.join()+right.join();
        }
    }
}

8、Optional的使用

我们之前写代码,要经常进行空值的判断,避免出现空指针异常。JDK8针对这一情况推出了Optional来改进这一情况!

首先来看一下之前对null值的处理情况吧!

代码语言:javascript
复制
	public static void main(String[] args) {
        Person p= new Person("张三",18);
        p=null;
        if(p!=null){
            System.out.println(p);
        }else{
            System.out.println("查无此人");
        }
    }
image20191231164652214.png
image20191231164652214.png

8.1、Optional类介绍

Optional是一个没有子类的工具类,Optional是一个可以为null的容器对象。它的作用主要就是为了解决避免Null检查,防止NullPointerException。

image20191231165217233.png
image20191231165217233.png

8.2、Optional类的创建方式:

代码语言:javascript
复制
Optional.of(T t):创建一个Optional实例
Optional.empty():创建一个空的Optional实例
Optional.ofNullable(T t):若t不为null,创建Optional实例,否则创建空实例
代码语言:javascript
复制
    //Optional.of(T t):创建一个Optional实例
	public static void main(String[] args) {
        Person p= new Person("张三",18);
        Optional<Person> p1 = Optional.of(p);//不能放空值
        Person person = p1.get();//获取对象
        System.out.println(person);
    }
image20191231230306292.png
image20191231230306292.png
image20191231231319502.png
image20191231231319502.png
image20191231235130795.png
image20191231235130795.png
image20191231235746538.png
image20191231235746538.png
image20191231235514487.png
image20191231235514487.png
代码语言:javascript
复制
    public static void main(String[] args) {
        Person p= new Person("张三",18);
        //Optional.ofNullable(T t):若t不为null,创建Optional实例,否则创建空实例
        Optional<Person> p1 = Optional.ofNullable(p);
        Person person = p1.get();
        System.out.println(person);
    }
image20200101000645913.png
image20200101000645913.png
image20200101121339917.png
image20200101121339917.png

8.3、Optional类的常用方法:

代码语言:javascript
复制
isPresent():判断是否包含值,包含值返回true,不包含值返回false
get():如果Optional有值则将其返回,否则抛出NoSuchElementException
orElse(T t):如果调用对象包含值,返回该值,否则返回参数t
orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回s获取的值
map(Function f):如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()
image20200101121801975.png
image20200101121801975.png
image20200101122148711.png
image20200101122148711.png
image20200101123402325.png
image20200101123402325.png
image20200101131845270.png
image20200101131845270.png
image20200101160143095.png
image20200101160143095.png

9、JDK8的时间和日期

9.1、旧版日期时间API存在的问题

1、设计很差:在Java.util和java.sql的包中都有日期类,java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期。此处用于格式化和解析的类在java.text包中定义。

2、非线程安全:java.util.Date是非线程安全的,所有的日期类都是可变的,这是java日期类最大的问题之一。

3、时区处理麻烦:日期类并不提供国际化,没有时区支持。因此Java引入了Java.util.Calendar和Java.util.TimeZone类,但他们同样存在上述所有的问题。

Date类的缺陷

代码语言:javascript
复制
    public static void main(String[] args) throws Exception {
        Date d = new Date(1990,1,1);
        System.out.println(d);
    }
image20200101231927774.png
image20200101231927774.png

日期解析和格式化缺陷

线程不安全

代码语言:javascript
复制
	public static void main(String[] args) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (int i=0;i<100;i++){
            new Thread(()->{
                Date d = null;
                try {
                    d = sdf.parse("2020-1-1");
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                System.out.println(d.toLocaleString());
            }).start();

        }
    }
image20200101232858717.png
image20200101232858717.png
image20200101233052852.png
image20200101233052852.png

9.2、新版本日期时间API介绍

JDK8中增加了一套全新的日期和时间API,这套API设计合理,是线程安全的。新的日期及时间API位于java.time包中,下面是一些关键类。

LocalDate:表示日期,包含年月日,格式为2019-10-16

LocalTime:表示时间,包含时分秒,格式为 16:38:54 158549300

LocalDateTime:表示日期时间,包含年月日,时分秒,格式为:2018-09-06T15:33:56.750

DateTimeFormatter:日期时间格式化类。

Instant:时间戳,表示一个特定的时间瞬间

Duration:用于计算两个时间(LocalTime,时分秒)的距离

Period:用于计算两个日期(LocalDate,年月日)的距离

ZonedDateTime:包含时区的时间

9.3、Java中的历法

java中使用的历法是ISO 8601日历系统,它是世界民用历法,也就是我们所说的公历。平年有365天,闰年有366天。此外Java 8还提供了4套其他历法,分别是:

​ ThaiBuddhistDate:泰国佛教历

​ MinguoDate:中华民国历

​ JapaneseDate:日本历

​ HijrahDate:伊斯兰历

9.4、JDK8的日期和时间类

LocalDate、LocalTime、LocalDateTime类的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。他们提供了简单的日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。

代码语言:javascript
复制
 	public static void main(String[] args) throws Exception {
        //LocalDate:表示日期,年、月、日
        //创建指定日期
        LocalDate fj = LocalDate.of(2020,1,1);
        System.out.println(fj);//2020-01-01
        //创建当前日期
        LocalDate now = LocalDate.now();
        System.out.println(now);
        //获取日期信息
        System.out.println(now.getYear());//获取年
        System.out.println(now.getMonthValue());//获取月
        System.out.println(now.getDayOfMonth());//日
        System.out.println(now.getDayOfWeek());//周几
    }
image20200102000432192.png
image20200102000432192.png
代码语言:javascript
复制
	public static void main(String[] args) throws Exception {
        //LocalTime:表示十分秒
        //得到当前时间对象
        LocalTime lt = LocalTime.now();
        System.out.println(lt);
        int hour = lt.getHour();//得到小时
        int minute = lt.getMinute();//得到分钟
        int second = lt.getSecond();//得到秒
        int nano = lt.getNano();//得到纳秒
        System.out.println(hour);
        System.out.println(minute);
        System.out.println(second);
        System.out.println(nano);
    }
image20200102093413552.png
image20200102093413552.png
代码语言:javascript
复制
	public static void main(String[] args) throws Exception {
        //获取当前日期和时间
        LocalDateTime ldt = LocalDateTime.now();
        //以下分别得到:年、月、日、时、分、秒、纳秒
        int year = ldt.getYear();
        int month = ldt.getMonthValue();
        int day = ldt.getDayOfMonth();
        int hour = ldt.getHour();
        int minute = ldt.getMinute();
        int second = ldt.getSecond();
        int nano = ldt.getNano();
        System.out.println(year);
        System.out.println(month);
        System.out.println(day);
        System.out.println(hour);
        System.out.println(minute);
        System.out.println(second);
        System.out.println(nano);
    }
image20200102094751708.png
image20200102094751708.png

对日期的修改,使用withAttribute方法,该方法会返回修改之后的日期时间对象,原来的日期时间对象不会发生改变。

修改日期

代码语言:javascript
复制
	public static void main(String[] args) throws Exception {
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);
        //修改年份
        LocalDateTime ldt2 = ldt.withYear(2022);
        System.out.println(ldt2);
    }
image20200102095558100.png
image20200102095558100.png

增加和减少年份

代码语言:javascript
复制
	public static void main(String[] args) throws Exception {
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);
        //增加和减少年份
        LocalDateTime localDateTime = ldt.plusYears(10);//增加年份
        System.out.println(localDateTime);
        //减少年份
        LocalDateTime localDateTime1 = localDateTime.minusYears(10);
        System.out.println(localDateTime1);
    }
image20200102100248798.png
image20200102100248798.png

年份的判断

代码语言:javascript
复制
	public static void main(String[] args) throws Exception {
        LocalDateTime ldt = LocalDateTime.now();
        LocalDateTime ldt2 = LocalDateTime.of(2019, 10, 10, 10, 10, 10);
        boolean after = ldt.isAfter(ldt2); //是否在ldt2之后
        System.out.println(after);
        boolean before = ldt.isBefore(ldt2);//是否在ldt2之前
        System.out.println(before);
        boolean equal = ldt.isEqual(ldt2);//是否和ldt2相等
        System.out.println(equal);
    }
image20200104101419093.png
image20200104101419093.png

JDK 8的时间格式化与解析

通过java.time.format.DateTimeFormatter类可以进行日期时间解析与格式化

JDK自带的时间、日期格式化模板

代码语言:javascript
复制
	public static void main(String[] args) throws Exception {
        LocalDateTime ldt = LocalDateTime.now();
        DateTimeFormatter isoDateTime = DateTimeFormatter.ISO_DATE_TIME;//jdk自带的时间日期格式化模板
        String format = isoDateTime.format(ldt);
        System.out.println(format);
    }
image20200104102548529.png
image20200104102548529.png

自定义时间、日期格式化模板

代码语言:javascript
复制
	public static void main(String[] args) throws Exception {
        LocalDateTime ldt = LocalDateTime.now();
        DateTimeFormatter zdy = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");//自定义解析模板
        String format = zdy.format(ldt);
        System.out.println(format);
    }
image20200104103401582.png
image20200104103401582.png

时间日期的解析

代码语言:javascript
复制
	public static void main(String[] args) throws Exception {
        LocalDateTime ldt = LocalDateTime.now();
        DateTimeFormatter zdy = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");//自定义解析模板
        LocalDateTime parse = LocalDateTime.parse("2020年01月04日 10时30分05秒", zdy);
        System.out.println(parse);
    }
image20200104104108548.png
image20200104104108548.png
代码语言:javascript
复制
	public static void main(String[] args) throws Exception {
        LocalDateTime ldt = LocalDateTime.now();
        DateTimeFormatter zdy = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");//自定义解析模板
        for (int i=0;i<100;i++){
            new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            LocalDateTime parse = LocalDateTime.parse("2020年01月04日 10时30分05秒", zdy);
                            System.out.println(parse);
                        }
                    }
            ).start();
        }
    }
image20200104104541374.png
image20200104104541374.png

Instant

Instant时间戳/时间线,内部保存了从1970年1月1日 00:00:00以来的秒和纳秒

代码语言:javascript
复制
	public static void main(String[] args) throws Exception {
        Instant now = Instant.now();
        System.out.println("当前时间戳="+now);
        System.out.println(now.getNano());//获取时间戳的纳秒值
        System.out.println(now.getEpochSecond());
        System.out.println(now.toEpochMilli());
        System.out.println(System.currentTimeMillis());
    }
image20200104105942818.png
image20200104105942818.png

Instant的加操作

image20200104110542794.png
image20200104110542794.png

计算时间和日期差

1、Duration:用于计算2个时间(LocalTime,时分秒)的距离

2、Period:用于计算2个日期(LocalDate,年月日)的距离

image20200107222700274.png
image20200107222700274.png
image20200107225408777.png
image20200107225408777.png

JDK8的时间矫正器

有时我们可能需要获得特定的日期。例如:将日期调整到“下个月的第一天”等操作。可以通过时间矫正器来进行。

TemporalAdjuster:时间校正器

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

TemporalAdjuster:时间校正器

image20200109090642797.png
image20200109090642797.png
代码语言:javascript
复制
//TemporaAdjuster:时间矫正器
//TemporalAdjusters:该类通过静态方法提供了大量的常用TemporalAdjuster的实现
public class Demo36 {

    public static void main(String[] args) throws Exception {
        LocalDateTime dateTime = LocalDateTime.now();
        //得到下个月的第一天
        TemporalAdjuster firsWeekDayOfNextMonth = (Temporal temporal) -> {
            LocalDateTime ldt = (LocalDateTime) temporal;//把temporal转换成LocalDateTime类型
            LocalDateTime nextMonth = ldt.plusMonths(1).withDayOfMonth(1);//调整时间,加一个月,加一个月后的第一天
            System.out.println(nextMonth);
            return nextMonth;//返回调整之后的时间
        };
    }
}
image20200109091317949.png
image20200109091317949.png
image20200109092531958.png
image20200109092531958.png
代码语言:javascript
复制
public static void main(String[] args) throws Exception {
        LocalDateTime dateTime = LocalDateTime.now();
        //得到下个月的第一天
        TemporalAdjuster firsWeekDayOfNextMonth = (Temporal temporal) -> {
            LocalDateTime ldt = (LocalDateTime) temporal;//把temporal转换成LocalDateTime类型
            LocalDateTime nextMonth = ldt.plusMonths(1).withDayOfMonth(1);//调整时间,加一个月,加一个月后的第一天
            System.out.println(nextMonth);
            return nextMonth;//返回调整之后的时间
        };

        LocalDateTime now = dateTime.with(firsWeekDayOfNextMonth);
//        LocalDateTime now2 = (LocalDateTime)firsWeekDayOfNextMonth;
        System.out.println(now);

    }

结果:

image20200109092658531.png
image20200109092658531.png

JDK8设置时间和日期的时区

Java8 中加入了对时区的支持,LocalDate、LocalTime、LocalDateTime是不带时区的,带时区的日期时间类分别为:ZonedDate、ZonedTime、ZonedDateTime。

其中每个时区都对应着ID,ID的格式为“区域/城市”。例如:Asia/Shanghai 等。

Zoneld:该类中包含了所有的时区信息

image20200109094137479.png
image20200109094137479.png
代码语言:javascript
复制
public static void main(String[] args) throws Exception {
        //获得所有的时区ID
//        ZoneId.getAvailableZoneIds().forEach(System.out::println);
        //创建世界标准时间
        final ZonedDateTime zonedDateTimeFromClock = ZonedDateTime.now(Clock.systemUTC());
        System.out.println(zonedDateTimeFromClock);//2020-01-09T01:44:36.951697400Z
        //创建一个当前时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);//2020-01-09T09:48:21.130519700
        //创建一个带时区的ZonedDateTime
        final ZonedDateTime zonedDateTimeFromZone = ZonedDateTime.now(ZoneId.of("Africa/Nairobi"));
        System.out.println(zonedDateTimeFromZone);//2020-01-09T04:48:21.131519700+03:00[Africa/Nairobi]
    }
image20200109095203946.png
image20200109095203946.png
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、Lambda表达式
  • 1.1、概述
  • 1.2、函数式接口
  • 1.3、Lambda表达式和匿名内部类
    • 1.3.1、匿名内部类
      • 1.3.2、Lambda表达式
      • 1.4、Lambda表达式详解
        • 1.4.1、Lambda表达式的标准写法
          • 1.4.2、Lambda表达式的省略写法
          • 2、JDK8接口的方法增强
            • 2.1、概述
              • 2.2、JDK1.8接口新增方法种类
                • 2.3、默认方法的定义和使用
                  • 2.3.1、默认方法的定义
                    • 2.3.2、默认方法的使用
                      • 2.4、静态方法的定义和使用
                        • 2.4.1、静态方法的定义
                        • 2.4.2、静态方法的使用
                      • 2.5、接口中静态方法和默认方法的区别
                      • 3、JDK提供的常用内置函数式接口
                        • 3.1、为什么JDK要提供这些常用内置函数接口?
                          • 3.2、常用的函数式接口如下
                            • 3.2.1、Supplier接口:供给型接口
                            • 3.2.2、Consumer接口:消费型接口
                            • 3.2.3、Function接口:转换型接口
                            • 3.2.4、Predicate接口:判断型接口
                        • 4、Lambda表达式的方法引用
                          • 4.1、Lambda表达式的方法引用的作用是什么?
                            • 4.2、方法引用的格式
                              • 4.3、常见引用方式
                                • 4.3.1、对象::方法名
                                • 4.3.2、类名::静态方法名
                                • 4.3.3、类名::方法名
                                • 4.3.4、类名::new (引用构造器)
                                • 4.3.5、数组类型::new
                              • 4.4、方法引用总结
                              • 5、Stream流
                                • 5.1、Stream流思想概述
                                  • 5.2、Stream流思想的体现案例
                                    • 5.3、获取Stream流的两种方式
                                      • 5.3.1、根据Collection的stream()方法获取流
                                      • 5.3.2、根据Stream类的静态of()方法
                                    • 5.5、Stream的注意事项
                                      • 5.4、Stream常用API
                                        • 5.6、Stream常用API演示
                                        • 6、并行的Stream流
                                          • 6.1、并行的Stream流的获取方式
                                            • 6.2、并行流的线程安全问题
                                            • 7、Fork/Join框架
                                              • 7.1、Fork/Join框架原理-分治法
                                                • 7.2、Fork/Join原理-工作窃取法
                                                  • 7.3、ForkJoin案例
                                                  • 8、Optional的使用
                                                    • 8.1、Optional类介绍
                                                      • 8.2、Optional类的创建方式:
                                                        • 8.3、Optional类的常用方法:
                                                        • 9、JDK8的时间和日期
                                                          • 9.1、旧版日期时间API存在的问题
                                                            • 9.2、新版本日期时间API介绍
                                                              • 9.3、Java中的历法
                                                                • 9.4、JDK8的日期和时间类
                                                                相关产品与服务
                                                                容器服务
                                                                腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                                                                领券
                                                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档