Java学废之路10——Java8新特性

本文详细介绍了Java8的新特性,包括速度更快的HashMap结构、Lambda表达式的语法与优缺点、函数式接口的自定义与核心接口,以及方法引用和构造器引用的使用。此外,还重点解析了Stream API的创建、中间操作和终止操作,展示了如何利用Stream进行高效的数据处理。
摘要由CSDN通过智能技术生成

JAVA8新特性

  • 速度更快
  • 代码更少——Lambda
  • 强大的Stream API
  • 便于并行
  • 最大化减少空指针异常——optional

零、速度更快

速度更快指的是hashMap的结构增加了红黑树。

image-20201018100342653

在之前的hashmap结构中,jdk采用的是数组+链表的方式进行。当发生碰撞时,会极大地降低查找的效率。所以在jdk1.8中,采用了数组+链表+红黑树的方式,前提是当发生碰撞的个数大于8时且总容量大于64时,才会将链表结构转换为红黑树,此时会造成添加元素的效率降低,但是查找和删除等的效率会大大提高:

image-20201018102515844

一、Lambda表达式

在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情” 。相对而言,面向对过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做。

  • 面向对象的思想:做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情。
  • 函数式编程思想:只要能获取到结果,谁去做的,怎么做的都不重要,重要的是结果,不重视过程。

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

//原来的匿名内部类
@Test
public void test1(){
   
    // 匿名内部类,即只存在实现的没有实例对象的类
    Comparator<String> com = new Comparator<String>(){
   
        @Override
        public int compare(String o1, String o2) {
   
            // 此句为核心的代码
            return Integer.compare(o1.length(), o2.length());
        }
    };
    TreeSet<String> ts = new TreeSet<>(com);
    
}

//现在的 Lambda 表达式
@Test
public void test2(){
   
    // 简化代码的书写,将核心代码抽取出来
    // Lambda表达式作为参数传递
    Comparator<String> com = (x, y) -> Integer.compare(x.length(), y.length());
    TreeSet<String> ts = new TreeSet<>(com);
}

1.1 语法

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

  • 左侧: 指定了 Lambda 表达式需要的所有参数
  • 右侧: 指定了 Lambda 体,即 Lambda 表达式要执行的功能
1.1.1 无参数,无返回值

image-20200828194036143

1.1.2 一个参数,无返回值

image-20200828194134690

1.1.3 若只有一个参数,小括号可以省略不写

image-20200828194224920

1.1.4 两个以上的参数,有返回值

image-20200828194303252

1.1.5 若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写

image-20200828194357393

1.1.6 参数列表的数据类型可以省略不写

image-20200828194436744

上述 Lambda 表达式中的参数类型都是由编译器推断得出的。 Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac编译器 根据程序的上下文,在后台推断出了参数的类型。 Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断” 。

1.2 优缺点

1.1.1 优点
  • 简洁。

  • 非常容易并行计算。

  • 可能代表未来的编程趋势。

  • 结合 hashmap 的 computeIfAbsent 方法,递归运算非常快。java有针对递归的专门优化。

1.1.2 缺点

由于省略了太多东西,代码可读性有可能在一定程度上会降低。

1.3 实现

拷贝小括号,写死右箭头,落地大括号

package com.zdp.java8;

import org.junit.Test;

import java.util.Comparator;
import java.util.function.Consumer;

/**
 * 一、Lambda 表达式的基础语法:Java8中引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符
 * 箭头操作符将 Lambda 表达式拆分成两部分:
 * <p>
 * 左侧:Lambda 表达式的参数列表
 * 右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体
 * <p>
 * 语法格式一:无参数,无返回值
 * () -> System.out.println("Hello Lambda!");
 * <p>
 * 语法格式二:有一个参数,并且无返回值
 * (x) -> System.out.println(x)
 * <p>
 * 语法格式三:若只有一个参数,小括号可以省略不写
 * x -> System.out.println(x)
 * <p>
 * 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
 * Comparator<Integer> com = (x, y) -> {
 * System.out.println("函数式接口");
 * return Integer.compare(x, y);
 * };
 * <p>
 * 语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
 * Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
 * <p>
 * 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
 * (Integer x, Integer y) -> Integer.compare(x, y);
 * <p>
 * 上联:左右遇一括号省
 * 下联:左侧推断类型省
 * 横批:能省则省
 * <p>
 * 二、Lambda 表达式需要“函数式接口”的支持
 * 函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 可以使用注解 @FunctionalInterface 修饰
 * 注解 @FunctionalInterface可以检查是否是函数式接口
 */
public class LambdaStudy01 {
   
    // Lambda体的作用是实现接口
    // 前提是该接口中只含有一个抽象方法(函数式接口)
    @Test
    public void test1() {
   
        // 同级别局部内部类
        int num = 0;//jdk 1.7 前,必须是 final

        // Runnable是一个无参无返回值的接口
        Runnable r = new Runnable() {
   
            @Override
            public void run() {
   
                // 匿名内部类引用同级别局部内部类
                System.out.println("Hello World!" + num);
            }
        };
        r.run();
        System.out.println("-------------------------------");

        // 语法格式一:无参数,无返回值
        Runnable r1 = () -> System.out.println("Hello Lambda!");
        r1.run();
    }

    // 语法格式二:有一个参数,并且无返回值
    @Test
    public void test2() {
   
        /**
         * Consumer是JAVA8中提供的一个函数式接口
         * Performs this operation on the given argument.
         *
         * @param t the input argument
         *
         * 内部含有一个有参方法
         * void accept(T t);
         */
        // Lambda表达式 即去实现这个接口中的唯一一个方法
        Consumer<String> consumer = (x) -> System.out.println(x);
        consumer.accept("zdp牛逼!!!");
    }

    // 语法格式三:若只有一个参数,小括号可以省略不写
    @Test
    public void test3() {
   
        Consumer<String> consumer = x -> System.out.println(x);
        consumer.accept("zdp牛逼!!!");
    }

    // 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
    @Test
    public void test4() {
   
        // 实现函数式接口
        Comparator<Integer> comparator = (a, b) -> {
   
            // 多条语句
            System.out.println("函数式接口");
            return Integer.compare(a, b);
        };

        // 执行
        int compare = comparator.compare(1, 2);
        System.out.println(compare);
    }

    // 语法格式五:若 Lambda 体中只有一条语句, return 和 大括号 都可以省略不写
    @Test
    public void test5() {
   
        // 实现函数式接口,实现时只有一条语句
        // 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写
        // 因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
        Comparator<Integer> comparator = (a, b) -> Integer.compare(a, b);

        // 执行
        int compare = comparator.compare(1, 2);
        System.out.println(compare);
    }
}

二、 函数式接口

  • 函数式接口有且仅有一个未被覆写的抽象方法。但是 Object 中方法不算,接口中的 default 方法和 static 方法也不算
/**
 * 函数式接口
 * 函数式接口有且仅有一个未被覆写的抽象方法。
 * 但是Object 中方法不算,接口中的 default 方法不算
 * 注解 @FunctionalInterface 修饰可以检查是否是函数式接口
 */
@FunctionalInterface
public interface FunctionalInterfaceTest {
   
    // 只含有一个抽象方法
    void test();

    // 默认实现方法除外
    default void defaultTest(){
   
        System.out.println("这是函数式接口的默认实现方法");
    }
    
    // 静态方法除外
    static void staticTest(){
   
        System.out.println("这是函数式接口的静态实现方法");
    }

    // Object的方法
    String toString();
    int hashCode();
    boolean equals(Object object);
}
  • 使用注解 @FunctionalInterface 修饰可以检查是否是函数式接口

    image-20200828195220990

default方法:

java8在接口中新增default方法,是为了在现有的类库中新增功能而不影响他们的实现类。试想一下,如果不增加默认实现的话,接口的所有实现类都要实现一遍这个方法,这会出现兼容性问题,如果定义了默认实现的话,那么实现类直接调用就可以了,并不需要实现这个方法。

// 增强的接口
public interface MyInterface01 {
    
    // 使用default关键字,增加接口方法的默认实现,该默认方法也可以被实现类重写
       default  void testInterFace(){
    
           System.out.println("增强接口的默认方法");
       }
       void test();
}

注意:如果接口中的默认方法不能满足某个实现类需要,那么实现类可以覆盖默认方法。不用加default关键字,例如:

// 增强接口的实现类
public class InterfaceTest implements MyInterface01 {
    
//    // 重写接口的默认方法,也可以不重写
//    @Override
//    public void testInterFace() {
    
//
//    }

    @Override
    public void test() {
    
        System.out.println("增强接口的test");
    }
   }

2.1 自定义函数式接口

/**
 * 函数式接口
 * 函数式接口有且仅有一个未被覆写的抽象方法。
 * 但是Object 中方法不算,接口中的 default 方法不算
 * 注解 @FunctionalInterface 修饰可以检查是否是函数式接口
 */
@FunctionalInterface
public interface FunctionalInterfaceDemo {
   
    // 只含有一个抽象方法
    Integer test(int x);

    // 默认实现方法除外
    default void defaultTest(){
   
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我姓弓长那个张

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

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

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

打赏作者

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

抵扣说明:

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

余额充值