JDK8新特性

JDK8新特性

1.截止目前,JDK比较重要的时间节点和版本说明

1996 JDK1.0
2004 JDK5.0最重要的一个里程碑式的版本
2014 JDK8.0排第二的里程碑式的版本----> LTS
2017.9 JDK9.0从此版本开始,每半年发布一个新的版本

2018.9 JDK11----> LTS
2021.9 JDK17----> LTS

2.如何学习新特性?

  • 角度1:新的语法规则(多关注)
    自动装箱、自动拆箱、注解、enum、Lambda表达式、方法引用、switch表达式、try-catch变化、record等
  • 角度2:增加、过时、删除API
    StringBuilder、ArrayList、新的日期时间的API、Optional等
  • 角度3:底层的优化、JVM参数的调整、GC的变化、内存结构(永久代--->元空间)|①

lambda表达式举例与语法.

  1. Lambda表达式的使用举例:
    (o1,o2) -> Integer.compare(o1,o2);
  2. Lambda表达式的格式举例:
  • : lambda操作符或箭头操作符
  • 的左边: lambda 形参列表,对应着要重写的接口中的抽象方法的形参列表。
  • 的右边: lambda体,对应着接口的实现类要重写的方法的方法体。
  1. Lambda表达式的本质:
  • 一方面,lambda表达式作为接口的实现类的对象。
  • "万事万物皆对象">另一方面,lambda表达式是一个匿名函数。
        //语法格式一:无参,无返回值
    public void test2() {
        Runnable r2 = new Runnable() {
            @Override
            public void run() {
                System.out.println("我爱中国2");
            }
        };
        r2.run();
    }
    //Lambda表达式的写法
    public void test1() {
        Runnable r1 = () -> System.out.println("我爱中国1");
        r1.run();
    }

    public void test3() {
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };
        System.out.println(com1.compare(23, 25));
    }

    //Lambda表达式的写法
    //语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且可以有返回值
    //语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略

    public void test4() {
        Comparator<Integer> com1 = (o1, o2) -> Integer.compare(o1, o2);
        System.out.println(com1.compare(23, 25));
    }

    //方法引用
    public void test5() {
        Comparator<Integer> com1 =  Integer::compare;
        System.out.println(com1.compare(63, 25));
    }

    //若只需要一个参数时,参数的小括号可以省略
    public void test6(){
        Consumer<String> consumer1=s -> System.out.println(s);
        consumer1.accept("时间你好");
    }

5.函数式接口:

5.1 什么是函数式接口?为什么需要函数式接口?

  • 如果接口中只声明有一个抽象方法,则此接口就称为函数式接口。
  • 因为只有给函数式接口提供实现类的对象时,我们才可以使用lambda表达式。

5.2 api中函数式接口所在的包

jdk8中声明的函数式接口都在java.util.function包下。

image-20230913125419073


02-方法引用.

1.举例;

Integer : : compare;

2.方法引用的理解

  • 方法引用,可以看做是基于lambda表达式的进一步刻画。

  • 当需要提供一个函数式接口的实例时,我们可以使用lambda表达式提供此实例。

    当满足一定的条件的情况下,我们还可以使用方法引用或构造器引用替换lambda表达式。

3.方法引用的本质:

方法引用作为了函数式接口的实例。 --->“万事万物皆对象”

4.格式:

类(或对象)::方法名

5.具体使用情况说明;

情况1: 对象 ∶: 实例方法

  • 要求:函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的形参列表和返回值类型都相同(或一致)(能装箱或父类)
  • 此时,可以考虑使用方法b实现对方法a的替换、覆盖。此替换或覆盖即为方法引用。
  • 注意:此方法b是非静态的方法,需要对象调用。
    //1
    public void test1() {

        Consumer<String> con1 = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con1.accept("aaaaaaa");

        //2. lambda表达式
        Consumer<String> con2 = (String s) -> System.out.println(s);
        con2.accept("bbbbbbbb");

        //3.方法引用
        //PrintStream printStream=System.out;
        Consumer<String> con3 = System.out::println;
        con3.accept("ccccccccc");
    }

    // Supplier中的T get()
    //Employee中的String getName()
    public void test2() {
        //1
        Person person = new Person("马化腾", 22);
        Supplier<String> sup1=new Supplier<String>() {
            @Override
            public String get() {
                return person.getName();
            }
        };
        System.out.println(sup1.get());

        //2
        Supplier<String> sup2=()-> person.getName();
        System.out.println(sup2.get());

        //3
        Supplier<String> sup3=person::getName;
        System.out.println(sup3.get());
    }

情况2: 类 :: 静态方法

  • 要求:函数式接口中的抽象方法a与其内部实现时调用的类的某个静态方法b的形参列表和返回值类型都相同。(或一致)
  • 此时,可以考虑使用方法b实现对方法a的替换、覆盖。此替换或覆盖即为方法引用。
  • 注意:此方法b是静态的方法,需要类调用。
    //情况二:类::静态方法
    // comparator中的int compare(T t1,T t2 )
    // Integer中的int compare(T t1,T t2)
    public void test3(){
        Comparator<Integer> com1=new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        };
        System.out.println(com1.compare(12,11));

        //2
        Comparator<Integer> com2=(o1, o2)->Integer.compare(o1,o2);
        System.out.println(com2.compare(12,11));

        //3
        Comparator<Integer> com3=Integer::compare;
        System.out.println(com3.compare(12,11));
    }

    //Function中的Rapply(T t)
    // Math中的Long round (Double d)
    public void test4(){
        Function<Double,Long> fun1=new Function<Double, Long>() {
            @Override
            public Long apply(Double aDouble) {
                return Math.round(aDouble);
            }
        };
        System.out.println(fun1.apply(5.1));

        //2
        Function<Double,Long> fun2=aDouble->Math.round(aDouble);
        System.out.println(fun2.apply(5.9));

        //3
        Function<Double,Long> fun3=Math::round;
        System.out.println(fun3.apply(5.9));
    }

情况3: 类 :: 实例方法

  • 要求:函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的返回值类型相同。
  • 同时,抽象方法a中有n个参数,方法b中有n-1个参数,且抽象方法a的第1个参数作为方法b的调用者,且抽象方法a的后n-1个参数与方法b的n-1个参数的类型相同(或一致)。则可以考虑使用方法b实现对方法a的替换、覆盖。此替换或覆盖
  • 注意:此方法b是非静态的方法,需要对象调用。但是形式上,写出对象a所属的类
    //情况三:类:︰实例方法(难)
    // Comparator中的int comapre(T t1,T t2)
    // String中的int t1.compareTo(t2)
    public void test5(){
        //1
        Comparator<String> com1=new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        };
        System.out.println(com1.compare("abc", "cbc"));

        //2
        Comparator<String> com2=(o1,o2)->o1.compareTo(o2);
        System.out.println(com2.compare("abc", "cbc"));

        //3
       Comparator<String> com3=String::compareTo;//因为方法调用者是形参,所以用其类表示
        System.out.println(com3.compare("abc", "cbc"));
    }

    //BiPredicate中的boolean test(T t1,T t2);
    // String中的boolean t1.equals(t2)
    public void test6(){
        BiPredicate<String,String> bip1=new BiPredicate<String, String>() {
            @Override
            public boolean test(String s, String s2) {
                return s.equals(s2);
            }
        };
        System.out.println(bip1.test("aa","aa"));

        //2
        BiPredicate<String,String> bip2=(s, s2)->s.equals(s2);
        System.out.println(bip2.test("aa","aa"));


        //3
        BiPredicate<String,String> bip3=String::equals;
        System.out.println(bip3.test("aa","aa"));
    }

03-构造器引用、数组引用

1.构造器引用

1.1格式:类名 : : new

1.2说明:

  • 调用了类名对应的类中的某一个确定的构造器
  • 具体调用的是类中的哪一个构造器呢?取决于函数式接口的抽象方法泛型的形参列表!
  //构造器引用
    //Supplier中的T get()
    public void test7(){
    //1
        Supplier<Person> sup1 =new Supplier<Person>() {
            @Override
            public Person get() {
                return new Person("ooo",2);
            }
        };
        System.out.println(sup1.get());

        //2
        Supplier<Person> sup2 =()->new Person("ooo",2);
        System.out.println(sup2.get());

        //3
        Supplier<Person> sup3 =Person::new ;//根据泛型,只能调用空参的
        System.out.println(sup3.get());
    }

    //BiFunction中的Rapply(T t,u u)
    public void test8(){
        BiFunction<String,Integer,Person> f1=new BiFunction<String, Integer, Person>() {
            @Override
            public Person apply(String s, Integer integer) {
                return new Person(s,integer);
            }
        };
        System.out.println(f1.apply("pp",22));

        //3
        BiFunction<String,Integer,Person> f2=Person::new;
        System.out.println(f2.apply("pp",22));

    }

2.数组引用

格式:数组名[]:: new

  //数组引用
    //Function中的Rapply(T t)
    public void test9() {
        Function<Integer,Person[]> f1=new Function<Integer, Person[]>() {
            @Override
            public Person[] apply(Integer integer) {
                return new Person[integer];
            }
        };

        //3
        Function<Integer,Person[]> f2=Person[]::new;

    }
}

5.Java8新特性:强大的Stream API

1 stream APIvs集合框架

  • Stream API关注的是多个数据的计算(排序、查找、过滤、映射、遍历等),面向CPU的。集合关注的数据的存储,向下内存的。
  • Stream API之于集合,类似于SQL之于数据表的查询。

2.使用说明

  • stream自己不会存储元素。
  • Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  • Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生结界。
  • stream一旦执行了终止操作,就不能再调用其它中间操作或终止操作了。

stream执行流程步骤

1: Stream的实例化步骤

   //创建Stream方式一:通过集合
    public void test1(){
        List<Student> list = StudentList.getStudent();
        //default Stream<E> stream() :返回一个顺序流
        Stream<Student> stream = list.stream();
        //default Stream<E> parallelStream() :返回一个并行流
        Stream<Student> stream1 = list.parallelStream();
        System.out.println(stream);//java.util.stream.ReferencePipeline$Head@36baf30c
        System.out.println(stream1);//java.util.stream.ReferencePipeline$Head@7a81197d

    }

    //创建Stream方式二:通过数组
    public void test2(){
        // 调用Arrays类的static <T> Stream<T> stream(T[ ] array):返回一个流
        Integer[] integers = {1, 2, 3, 4, 5};
        Stream<Integer> stream = Arrays.stream(integers);
        System.out.println(stream);

    }

    //创建Stream方式三:通过Stream的of()
    public void test3(){
        Stream<String> stream = Stream.of("aa", "bb", "ccc", "pp");

    }

2:一系列的中间操作步骤

package com.xin.lambda.demo02;

import java.util.Objects;

public class Student {

    private int id;
    private String name;
    private int age;
    private double wage;

    public Student() {
    }

    public Student(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Student(int id, String name, int age, double wage) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.wage = wage;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getWage() {
        return wage;
    }

    public void setWage(double wage) {
        this.wage = wage;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", wage=" + wage +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return id == student.id && age == student.age && Double.compare(student.wage, wage) == 0 && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, age, wage);
    }
}
========
    package com.xin.lambda.demo02;

import java.util.ArrayList;
import java.util.List;

public class StudentList {

    public static List<Student> getStudent(){
        ArrayList<Student> list = new ArrayList<>();
        list.add(new Student(1001,"aaa",22,8888));
        list.add(new Student(1002,"bbb",11,5485));
        list.add(new Student(1003,"ccc",58,2212));
        list.add(new Student(1004,"dddd",47,2225));
        list.add(new Student(1005,"eee",15,9999));
        return list;
    }
}
==========
    package com.xin.lambda.demo02;

import junit.framework.TestCase;

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

public class Day91401 extends TestCase {

    //1-筛选与切片
    public void test1() {
        //filter(Predicate p)——接收Lambda,从流中排除某些元素。
        // 练习:查询员工表中薪资大于7000的员工信息
        List<Student> list = StudentList.getStudent();
        Stream<Student> stream = list.stream();
        stream.filter(s -> s.getWage() > 7000).forEach(System.out::println);

        System.out.println();
        //limit(n)--截断流,使其元素不超过给定数量。
        //错误的。因为stream已经执行了终止操作,就不可以再调用其它的中间操作或终止操作了。
        //stream.limit(1).forEach(System.out::println);
        list.stream().filter(s -> s.getAge() > 20).limit(2).forEach(System.out::println);

        System.out.println();
        //skip(n)--跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。
        list.stream().skip(2).forEach(System.out::println);

        System.out.println();
        //distinct()--筛选,通过流所生成元素的 hashCode() 和equals()去除重复元素
        list.add(new Student(1055, "oooo", 55, 7777));
        list.add(new Student(1055, "oooo", 55, 7777));
        list.add(new Student(1055, "oooo", 55, 7777));
        // System.out.println(list);

        list.stream().distinct().forEach(System.out::println);
    }


    //2 映射
    public void test2() {
        //map(Function f)--接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会被应用到每个元素
        // 练习:转换为大写
        List<String> list = Arrays.asList("aa", "bb", "vv", "yy");
        //方式1
        //list.stream().map(s->s.toUpperCase()).forEach(System.out::println);
        //方式2
        list.stream().map(String::toUpperCase).forEach(System.out::println);

        //练习:获取员工姓名长度大于3的员工的姓名。
        List<Student> list1 = StudentList.getStudent();
        Stream<Student> stream = list1.stream();
        // stream.filter(s->s.getName().length()>3).map(s->s.getName()).forEach(System.out::println);
        // stream.map(s->s.getName()).filter(n->n.length()>3).forEach(System.out::println);
        stream.map(Student::getName).filter(n -> n.length() > 3).forEach(System.out::println);
    }


    //3-排序
    public void test3() {
        //sorted()--自然排序
        Integer[] arr = {45, 978, 45, 22, 1, 56, 34, 77};
        String[] arr1={"ss","ii","oo","aa"};
        Arrays.stream(arr).sorted().forEach(System.out::println);

        System.out.println(Arrays.toString(arr));//arr数组并没有因为升序,做调整。

        Arrays.stream(arr1).sorted(String:: compareTo).forEach(System.out::println);
    }
    public void test4(){
    // sorted(Comparator com)——定制排序
        List<Student> list = StudentList.getStudent();
        list.stream().sorted((s1,s2)->s1.getAge()-s2.getAge()).forEach(System.out::println);

    }
}

3:执行终止操作

    //1-匹配与查找
    public void test1() {
        // allMatch(Predicate p)——检查是否匹配所有元素。
        //练习:是否所有的员工的年龄都大于18
        List<Student> list = StudentList.getStudent();
        System.out.println(list.stream().allMatch(student -> student.getAge() > 18));

        //anyMatch(Predicate p)—-检查是否至少匹配一个元素。
        // 练习:是否存在员工的工资大于8888
        System.out.println(list.stream().anyMatch(student -> student.getWage() > 8888));

        //findFirst—-返回第一个元素
        System.out.println(list.stream().findFirst());//Optional[Student{id=1001, name='aaa', age=22, wage=8888.0}]
    }

    public void test2() {
        //count——返回流中元素的总个数
        List<Student> list = StudentList.getStudent();
        System.out.println(list.stream().count());

        //max(Comparator c)─-返回流中最大值
        ////练习:返回最高工资的员工
        System.out.println(list.stream().max((s1, s2) -> Double.compare(s1.getWage(), s2.getWage())));
        // System.out.println(list.stream().max((s1, s2) -> (int) (s1.getWage()-s2.getWage())));

        // 练习:返回最高的工资:
        //System.out.println(list.stream().max((s1, s2) -> Double.compare(s1.getWage(), s2.getWage())).get().getWage());
        // System.out.println(list.stream().map(student -> student.getWage()).max((w1,w2)->Double.compare(w1,w2)));
        System.out.println(list.stream().map(student -> student.getWage()).max(Double::compareTo));

        //min(Comparator c)--返回流中最小值练习:返回最低工资的员工
        System.out.println(list.stream().map(student -> student.getWage()).min(Double::compareTo));

        //forEach(Consumer c)—-内部迭代
        list.stream().forEach(System.out::println);

        //针对于集合,jdk8中增加了一个遍历的方法
        list.forEach(System.out::println);
        //针对于List来说,遍历的方式:①使用Iterator增强for一般for ④ forEach()

    }

    //归约
    public void test3(){
        //reduce(T identity,BinaryOperator)--可以将流中元素反复结合起来,得到一个值。返回
        // 练习1:计算1-10的自然数的和
        List<Integer> list= Arrays.asList(1,2,3,4,5,6,7,8,9);
        System.out.println(list.stream().reduce(0, (x1, x2) -> x1 + x2));//45
        System.out.println(list.stream().reduce(10, (x1, x2) -> x1 + x2));//55

        System.out.println(list.stream().reduce(0, (x1, x2) -> Integer.sum(x1,x2)));
        System.out.println(list.stream().reduce(0,Integer::sum));


    //reduce(Binary0perator)--可以将流中元素反复结合起来,得到一个值。返回0ptional<T>
        // 练习2:计算公司所有员工工资的总和
        List<Student> list1 = StudentList.getStudent();
       // System.out.println(list1.stream().map(s -> s.getWage()).reduce((w1, w2) -> Double.sum(w1, w2)).get());
        System.out.println(list1.stream().map(s -> s.getWage()).reduce( Double::sum));

    }

    //收集
    public void test4(){
    //collect(Collector c)--将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
        // 练习1:查找工资大于6000的员工,结果返回为一个List或Set
        List<Student> list = StudentList.getStudent();
        List<Student> list1 = list.stream().filter(student -> student.getWage() > 3000).collect(Collectors.toList());
        //System.out.println(list1);
        list1.forEach(System.out::println);

        System.out.println();
        //练习2:按照员工的年龄进行排序,返回到一个新的List中
        List<Student> list2 = list.stream().sorted((s1, s2) -> s1.getAge() - s2.getAge()).collect(Collectors.toList());
        list2.forEach(System.out::println);

    }
posted @   新至所向  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示