首页 > 其他分享 >JDK8新特性

JDK8新特性

时间:2024-07-10 21:25:49浏览次数:10  
标签:name void 特性 JDK8 static println public String

  1. lambda表达式
  2. 函数式接口
  3. 方法引用
  4. stream流
  5. 日期时间类 

 1.lambda表达式

lambda表达式允许把函数作为一个方法的参数(函数作为方法参数进行传递),将代码像数据一样传递。特殊的匿名内部类,语法更加简洁

  

注意:函数式接口接口中只有一个抽象方法 

传统方式 

public class Test01 {
    public static void main(String[] args) {
        old task01 = new old();
        Thread tread01 = new Thread(task01);
        tread01.start();

        //匿名内部类
        Runnable task02 = new Runnable() {
            public void run() {
                System.out.println("这是匿名内部类");
            }
        };
        Thread thread02 = new Thread(task02);
        thread02.start();

        
    }

}
class old implements Runnable{

    public void run() {
        System.out.println("自定义接口类");
    }
}
  • Thread类需要Runnable接口作为参数,其中抽象run方法是用来指定线程任务内容的核心
  • 为了制定run的方法体,不得不需要Runnable接口的实现类
  • 为了省去定义一个Runnable实现类的麻烦,不得不使用匿名内部类
  • 而使用匿名内部类必须覆盖重写run方法,所以方法名称,方法参数,方法返回值不得不再写一遍,且不能写错
  • 而实际上,似乎只有方法体才是关键所在;

这是可以使用lambda表示完成上面的要求 

//lombda表达式
        Runnable task03 = () -> {
            System.out.println("这是lombda表达式");
        };
        Thread thread03 = new Thread(task03);
        thread03.start();

前提是必须是函数式接口

.无参无返回值的lambda表达式 

public class Test02 {
    public static void main(String[] args) {
        MyInterface myInterface = new MyInterface(){

            @Override
            public void say() {
                System.out.println("这是使用匿名实现类");
            }
        };
        test01(myInterface);
        /*========================================*/
        /*那是不是可以这样写*/
        MyInterface myInterface1 = ()->{
            System.out.println("这是使用lambda表达式01");
        };
        test01(myInterface1);
        /*========================================*/
        /*那是不是也可以这样写*/
        /*lambda表达式允许把函数作为一个方法的参数*/
        test01(()->{
            System.out.println("这是使用lambda表达式02");
        });

    }


    public static void test01(MyInterface myInterface) {
        myInterface.say();
    }

    interface MyInterface {
        public void say();
    }
}

.有参无有返回值的lambda表达式

public class Test03 {
    public static void main(String[] args) {
        ArrayList<User> users01 = new ArrayList<>();
        ArrayList<User> users02 = new ArrayList<>();
        users01.add(new User("张三", 20, "男"));
        users01.add(new User("李四", 21, "女"));
        users01.add(new User("王五", 22, "男"));
        users02.add(new User("张三", 20, "男"));
        users02.add(new User("李四", 21, "女"));
        users02.add(new User("王五", 22, "男"));
        //对集合按年龄大小排列
        //传统做法:Comparator:排列规则接口
        /*>0  o2比o1大
        * =0  o1和o2一样大
        * <0  o2比o1小*/
        Comparator<User> userComparator01 = new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o2.getAge() - o1.getAge();
            }
        };
        Collections.sort(users01, userComparator01);
        /*================================================================*/
        /*Lambda表达式*/
        Collections.sort(users02, (User o1, User o2)->{
            return o2.getAge() - o1.getAge();
        });
    }
}
/*实体类*/
class User{
    public String name;
    public int age;

    public User(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public  String sex;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }

    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 String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

 

注意事项

  • 形参列表的数据类型会自动推断
  • 如果形参列表为空,只需保留()-——参考无参
  • 如果形参只有1个,()可以省略,只需要参数的名称即可
  • 如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,若想省去{},则必须同时省略return,且执行语句也保证只有一句
  • Lambda不会生成一个单独的内部类文件   
  • Lambda表达式在编译时不生成独立的.class文件,而是被转换为一个合成类,并嵌入在包含Lambda的主类字节码中。

  • 这种设计减少了磁盘空间使用,减轻了类加载器的负担,并简化了类路径管理。

  • 在运行时,JVM通过动态类型生成机制处理Lambda表达式,利用invokedynamic指令动态创建和调用必要的类实例。

2.函数式接口 

如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口
可以使用Lambda表达式,Lambda表达式会被匹配到这个抽象方上
@Functionallnterface 注解检测接口是否符合函数式接口。 

public class Test01 {
    public static void main(String[] args) {
        fun(arr -> {
            int sum = 0;
            for (int n: arr) {
                sum += n;
            }
            System.out.println("数组的和为"+sum);
        });
    }
    public static void fun(Operater operater){
        int[] arr = {1,2,3,4,5,6,7,8,9,10};
        operater.getSum(arr);
    }
}
@FunctionalInterface
interface Operater {
    //求数组的和
    public abstract void getSum(int[] arr);
}

 分析
我们知道使用Lambda表达式的前提是需要有函数式接口。而Lambda使用时不关心接口名,抽象方法名,只关心抽 象方法的参数列表和返回估类里,因此为了让我们使用Lambda方便,JDK提供了大量常用的函数式接口

常见的函数接口 

2.1  Consumer<T> 消费性接口 

有参无返回值时,使用 Consumer<T> 消费性接口 

public class Test02 {
    public static void main(String[] args) {
        Consumer<Double> consumer = money->{
            System.out.println("消费了"+money+"元");
        };
        fun(consumer,1000);
    }
    public static void fun(Consumer<Double> consumer,double money){
        consumer.accept(money);
    }
}

 2.2  Supplier<T>  供给型接口

无参,但想要返回结果的函数式接口时,使用Supplier<T>  供给型接口

T代表返回结果的泛型

public class Test03 {
    public static void main(String[] args) {
        Supplier<Integer> supplier = () -> new Random().nextInt(10);
        fun(supplier);
    }
    public static void fun(Supplier<Integer> supplier) {
        Integer result = supplier.get();
        System.out.println("内容为" +result);

    }
}

2.3 Function<T,R> 函数型接口

 有参,有返回值时,使用 Function<T,R> 函数型接口

T:参数类型的泛型

R:函数返回结果的泛型

传入一个字符串把小写转化为大写

public class Test04 {
    public static void main(String[] args) {
        fun(s->s.toUpperCase(),"hello");
    }
    public static void fun(Function<String,String> function,String str){
        String s = function.apply(str);
        System.out.println("结果为" +s);
    }
}

2.4  Predicate <T> 断言型接口

当传入一个参数,需要对该参数进行判断时,使用Predicate <T> 断言型接口;

T:传入参数的泛型

public class Test05 {
    public static void main(String[] args) {
        fun(s -> s.length() > 3, "小鸟游六花");
    }
    public static void fun(Predicate<String> predicate, String name) {
        boolean test = predicate.test(name);
        System.out.println("该名字长吗" +test);
    }
}

3.方法引用

3.1 lambda表达式的冗余

public class Test06 {
    public static void main(String[] args) {
        Integer[] arr1 = {1,2,3,4,5};
        Consumer<Integer[]> consumer = (arr2->{
            int sum = 0;
            for(Integer a:arr2){
                sum+=a;
            }
            System.out.println("数组的和为"+sum);
        });
         fun(consumer,arr1);
       
    }
    public static void fun(Consumer<Integer[]> consumer, Integer[] arr){
        consumer.accept(arr);
    }

    public static void sum(Integer[] arr){
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
        System.out.println("数组的和为"+sum);
    }
}

如上,如果我们在Lambda中所需的功能已经在另一个方法中写出,直接引用过去就好了

public class Test06 {
    public static void main(String[] args) {
        Integer[] arr1 = {1,2,3,4,5};
        //双冒号::用法。这被称为方法引用,是一种新的语法,允许您引用类中的方法。
        Consumer<Integer[]> c=Test06::sum;
        fun(c,arr1);
    }
    public static void fun(Consumer<Integer[]> consumer, Integer[] arr){
        consumer.accept(arr);
    }

    public static void sum(Integer[] arr){
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
        System.out.println("数组的和为"+sum);
    }
}

3.2 方法引用的分类

方法引用是Lambda表达式的一种简写形式。如果lambda表达式方法体中只是一个调用一个特点定的已经存在的方法,则可以使用方法引用。

 

 3.2.1  静态方法引用

public class Test07 {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(3);
        list.add(1);
        list.add(7);
        list.add(2);
        //使用传统方法
        /*Comparator<Integer> comparator01 =(o1,o2)->Integer.compare(o1,o2);
        list.sort(comparator01);*/
        //使用静态方法引用
        //如果在lambda表达式中有且仅有一条语句,而且这条语句是对方法的调用。
        //这时可以考虑使用方法引用。
        Comparator<Integer> comparator02 = Integer::compare;
        list.sort(comparator02);
        System.out.println(list);
    }
}

3.2.2 实例方法引用

实例方法引用,顾名思义就是调用已经存在的方法,与静态方法引用不同的是类要先实例化,静态方法引用类无需实例化,直接用类名去调用.

public class Test08 {
    public static void main(String[] args) {
        Student student = new Student(18, "张三");
        // 传统做法
        Supplier<String> s1 = ()->student.getName();
        //实例化方法引用
        Supplier<String> s2 = student::getName;
        fun(s2);
    }
    public static void fun(Supplier<String> supplier){
        String s = supplier.get();
        System.out.println("姓名是" +s);
    }
}

class Student{
    public int age;
    public String name;

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

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

 3.2.3 对象方法引用

若lambda参数列表中的第一个参数是实例方法的参数调用者, 而第二个参数是实例方法的参数时,可以使用对象方法引用。

public class Test09 {
    public static void main(String[] args) {
        //传统方法
        //判断字符串长度
        Function<String,Integer> function=(s -> s.length());
        Integer hello = function.apply("hello");
        System.out.println(hello);
        //对象方法引用
        Function<String,Integer> function1=String::length;
        Integer hello1 = function1.apply("hello");
        System.out.println(hello1);
    }
}
public class Test09 {
    public static void main(String[] args) {
        //传统方法
        //判断两个字符串相同
        BiFunction<String,String,Boolean> function=(s, s1) -> s.equals(s1);
        boolean apply = function.apply("hello", "hell");
        System.out.println(apply);
        //对象方法引用
        BiFunction<String,String,Boolean> function1=String::equals;
        boolean hello1 = function1.apply("hello", "hell");
        System.out.println(hello1);
    }
}

3.2.4 构造方法引用

构造方法引用允许我们以更简洁的方式表达创建对象的过程,‌而不是显式地调用构造函数。‌

public class Test10 {
    public static void main(String[] args) {
        //传统方法
        Function<String,Person> function1 = (n) -> {
            return new Person(n);
        };
        Person person1 = function1.apply("张三");
        System.out.println(person1);
        //构造方法引用
        Function<String,Person> function2 = Person::new;
        Person person2 = function2.apply("李四");
        System.out.println(person2);
    }
}
class Person{
    public String name;
    public Person(String name) {
        this.name = name;
    }

    public Person() {

    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

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

 4.Stream流

java8的两个重大改变,应该是lambda表达式,另一个就是Stream API表达式。Stream是java8中处理集合的关键抽象概念,它可以对集合进行法非常复杂的查找,过滤,筛选等操作。

 4.1 为什么使用Stream流

当我们需要对集合中的元素进行操作时,除了必要的添加,删除,获取外,最典型的就是集合遍历,我们来体验集合操作的弊端,需求如下:    

public class Test01 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");
        //1.拿到所有姓张的
        ArrayList<String> zhangList = new ArrayList<>();
        for (String name : list) {
            if(name.startsWith("张")){
                zhangList.add(name);
            }
        }
        System.out.println(zhangList);
        //2.拿到名字长度长度为3的
        ArrayList<String> threeList = new ArrayList<>();
        for (String name : zhangList) {
            if(name.length() == 3){
                threeList.add(name);
            }
        }
        System.out.println(threeList);
        //打印这些数据
        for (String name : threeList) {
            System.out.println(name);
        }
    }
}

 这串代码中含有三个循环,每一个作用不同:

  1. 首先筛选所有姓张的人;
  2. 然后筛选名字有三个字的人;
  3. 最后进行对结果进行打印输出。

每当我们对集合中的元素进行操作时候,总是需要进行循环,循环,再循环,这是理所当然的吗?不是。循环式做事情的方式,而不是目的。每个需求都要循环一次,还要搞一个新集合来装数据,如果希望再次遍历,只能再使用一个循环从头开始。

那Stream能带给我们怎样更加优雅的写法呢?

public class Test02 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");
        //将集合转为stream流
        list.stream()
                //filter断言型接口
                .filter(s -> s.startsWith("张")).
                filter(s -> s.length() == 3)
                .forEach(System.out::println);
    }
}

 优点:对集合的操作简洁,性能比传统快,适合多线程

4.2 Stream流的原理

 注意:Stream和IO流没有任何关系,请暂时忘记对传统IO流的固有印象

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

Stream不存在数据,只对数据进行加工处理。

Stream有如下三个操作步骤 

 一,创建Stream

从一个数据源,如集合,数组中获取流 

 二,中间操作

一个操作的中间链,对数据源的数据进行操作

三,终止操作

一个终止操作,执行中间操作链,并产生结果

4.3 Stream流对象的获取方式 

  • 通过Collection对象的stream()或parallelStream()方法
  • 通过Arrays类的stream方法
  • 通过Stream接口的of(),iterate(),generate()方法
  • 通过IntStream,LongStream,DoubleStream接口中的of,range,rangeClosed方法
//通过集合对象调用stream()获取流对象
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"张三","李四","王五","赵六","田七");
        Stream<String> stream = list.stream();
        //通过数组(Arrays)工具类获取流对象
        int [] arr = {1,2,3,4,5,6,7,8,9,10};
        IntStream stream1 = Arrays.stream(arr);
        //使用Stream类的静态方法of()获取流对象
        Stream<String> stream2 = Stream.of("张三","李四","王五","赵六","田七");
        //通过LongStream工具类获取流对象
        LongStream range = LongStream.range(1, 10);

 上面都是获取的串行流(顺序流),该可以获取并行流

 stream和parallelStream的简单区分:stream是顺序流,由主线程按顺序执行操作,而parallelStream是并行流,内部以多线程并行的方法对流进行操作,但前提是流中数据处理没有顺序要求。例如筛选集合中的奇数。如果流中的数据量足够大,并行流可以加快处速读。两者的处理的不同之处:

 

//上面都是获取的串对象,还可以获取并行流对象
        Stream<String> parallelStream = list.parallelStream();
        //使用实例方法forEach()遍历流对象
        stream.forEach(System.out::println);
    }

4.4 Stream流中常见的api

中间操作api:一个操作的中间链,对数据源的数据进行操作,而这种操作的返回类型还是一个Stream对象。

终止操作api:一个终止操作,执行中间操作链,并产生结果,返回类型不在是Stream流对象。

 

以下内容可观看Java8中Stream详细用法大全_java stream()-CSDN博客,这里不详细讲解

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

标签:name,void,特性,JDK8,static,println,public,String
From: https://blog.csdn.net/m0_72156649/article/details/140226748

相关文章

  • Cilium Socket LB 特性
    CiliumSocketLB一、环境信息主机IPubuntu172.16.94.141软件版本docker26.1.4helmv3.15.0-rc.2kind0.18.0kubernetes1.23.4ubuntuosUbuntu20.04.6LTSkernel5.11.5内核升级文档二、CiliumSocketLB模式认知负载均衡的实......
  • 小特性 大用途 —— YashanDB JDBC驱动的这些特性你都get了吗?
    在现代数据库应用场景中,系统的高可用性和负载均衡是确保服务稳定性的基石。YashanDBJDBC驱动通过其创新的多IP配置特性,为用户带来了简洁而强大的解决方案,以实现数据库连接的高可用性和负载均衡,满足企业级应用的高要求。01多IP配置:构建高可用性的基础YashanDBJDBC驱动支持通......
  • c++新特性
    1.c++17新特性[[fallthrough]] 属性:这个属性用于在switch语句中。通常,当switch语句的一个case执行完毕后,会自动跳转到switch语句的末尾,除非存在break语句。如果你想要故意从一个case“落入”(fallthrough)到下一个case,可以使用[[fallthrough]]属性来告诉编译器这是故意的行为,以......
  • JDK8的型特性
             Java8(又称为jdk1.8)是Java语言开发的一个主要版本。Oracle公司于2014年3月18日发布Java8,它支持函数式编程,新的JavaScript引擎,新的日期API,新的StreamAPI等。        jdk8的官网What'sNewinJDK8(oracle.com)   ......
  • Lambda架构与Kappa架构的特性对比
        一个大数据系统架构的设计思想很大程度上受到当时技术条件和思维模式的限制。Lambda架构将批处理层和速度层分为两层,分别进行离线数据处理和实时数据处理,这样设计的根本原因在于,Lambda提出的初期是在公司中进行小范围的业务运用,当时并没有思考有没有一个计算引擎能......
  • C++八股(二)之C++11新特性
    一、C++11有什么新特性?⭐自动类型推导(TypeInference):引入了auto关键字,允许编译器根据初始化表达式的类型自动推导变量的类型。统一的初始化语法(UniformInitializationSyntax):引入了用花括号{}进行初始化的统一语法,可以用于初始化各种类型的对象,包括基本类型、数组、......
  • MySQL8.0索引新特性
    文章目录1支持降序索引2隐藏索引1支持降序索引举例:分别在MySQL5.7版本和MySQL8.0版本中创建数据表ts1,结果如下:CREATETABLEts1(aint,bint,indexidx_a_b(a,bdesc));在MySQL5.7版本中查看数据表ts1的结构,从结果可以看出,索引仍然是默认......
  • 【JDK8】新特性(二)
    6.StreamAPIJava8的两个重大改变,一个是Lambda表达式,另一个就是StreamAPI表达式。Stream是java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的査找、过滤、筛选等操作.6.1为什么使用stream流当我们需要对集合中的元素进行操作的时候,除了必需的添加、删除、获取......
  • HTTP协议30 丨 2特性概览
    刚结束的“安全篇”里的HTTPS,通过引入SSL/TLS在安全上达到了“极致”,但在性能提升方面却是乏善可陈,只优化了握手加密的环节,对于整体的数据传输没有提出更好的改进方案,还只能依赖于“长连接”这种“落后”的技术(参见第17讲)。所以,在HTTPS逐渐成熟之后,HTTP就向着性能方面......
  • HTTP协议27丨更好更快的握手:TLS1.3特性解析
    上一讲中我讲了TLS1.2的握手过程,你是不是已经完全掌握了呢?不过TLS1.2已经是10年前(2008年)的“老”协议了,虽然历经考验,但毕竟“岁月不饶人”,在安全、性能等方面已经跟不上如今的互联网了。于是经过四年、近30个草案的反复打磨,TLS1.3终于在去年(2018年)“粉墨登场”,再......