栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java 8 新特性 + 实例

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java 8 新特性 + 实例

从实用的角度出发,总结一下经常能用到的一些特性!

文章目录
  • 1、Lambda 表达式
    • 1.1 是什么?
    • 1.2 Lambda表达式基本格式 / 语法
  • 2、方法引用
  • 3、默认方法
  • 4、Stream API
  • 5、Date Time API
  • 6、Optional 类
  • 7、并发集合,并行数组
  • 8、JVM的改变
  • 9、锁的优化

1、Lambda 表达式

网上解释众说纷纭,以下也是我师傅的个人理解,是理解这个表达式来的过程。

1.1 是什么?

Lambda表达式是一个 有且只有一个实例抽象方法的接口 的 匿名实现类 的 简洁替身。

其中 有且只有一个实例抽象方法的接口 就是所谓的 “函数式接口”

什么是函数式接口?

1、接口中有且仅有一个 实例抽象方法
2、允许定义default实例抽象方法与静态非抽象方法
3、允许重写Object中的public方法
4、@FunctionInterface注解不是必须的,它的存在只为了编译器更好的检查,含有该注解,但是不符合上述要求时会编译错误

简化一下就是:

Lambda表达式是一个函数式接口 的 匿名实现类 的 简洁替身

还是拗口是吗?不要急,下面有个例子就能理解这个“定义”的来由了

场景是这样,有一个学生类,需要根据名字,年龄,分数进行一个排序

可以看到我们需要实现自定义的排序规则,需要,定义类,最简洁也得定义一个匿名内部类,来重写compare方法来实现我们的需求。然后去调用我们自己重写的方法

在这里我默认大家是知晓Lambda表达式的基本语法!当引入 Lambda表达式的概念以后,就可以根据其语法来进行 简化 我们的上述操作。对于下面的run方法,我们直接使用Lambda表达式来将上面具体的实现(函数)进行“传递”(Lambda 允许把函数作为一个方法的参数)

这样,回头再看,这个概念

Lambda表达式是一个函数式接口 的 匿名实现类 的 简洁替身

是不是清晰一点?我们暂时不需要明白它为什么可以这么做,只要明白,这么做,不需要定义匿名内部类,直接传递,这样可以少些一些代码。尽管这样理解有一点浅薄,但确是一个深入理解>Lambda表达式,不错的出发方向。

1.2 Lambda表达式基本格式 / 语法

(parameters) -> expression 或 (parameters) ->{ statements; }
也就是说,形如以上规则,将参数列表,通过特定符号->传入一个表格式亦或是代码块,这样的一个表达式,我们就称其为 Lambda表达式。

同理,我们也不需要知道为什么是这样,只需要知道,这样可以用,Java8认识它就好。

其他:

  • 类型可推断时,可以省略类型

    Test t = (String s) -> {System.out.println(s);}
    =>
    Test t = (s) -> {System.out.println(s);}

  • 有且只有一个参数时,无需定义圆括号,但无参和多个参数需要定义圆括号

    Test t = (String s) -> {System.out.println(s);}
    =>
    Test t = s -> {System.out.println(s);}

  • 如果主体只包含一个语句,就不需要使用大括号,包括语句后的分号。

    Test t = (String s) -> {System.out.println(s);}
    =>
    Test t = s -> System.out.println(s)

  • 如果主体只包含一个带返回值的表达式,则可以省略return关键字

    s -> rerutn func(s)
    =>
    s -> func(s)

2、方法引用

双冒号语法

方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

  • 构造器引用:它的语法是Class::new,或者更一般的Class< T >::new

    需要注意的是,构造方法必须是函数式接口的参数

  • 静态方法引用:它的语法是Class::static_method

  • 特定类的任意对象的方法引用:它的语法是Class::method

  • 特定对象的方法引用:它的语法是instance::method

public class Car {
   public static Car create( final Supplier< Car > supplier ) {
        return supplier.get();
    }

    public static void collide( final Car car ) {
        System.out.println( "Collided " + car.toString() );
    }

    public void follow( final Car another ) {
        System.out.println( "Following the " + another.toString() );
    }

    public void repair() {
        System.out.println( "Repaired " + this.toString() );
    }
    public static void main(String[] args) {
        Car car = Car.create(Car::new);
        List< Car > cars = Arrays.asList(car);
        cars.forEach(Car::collide);
        //...
    }
    
}

通过方法引用,可以将方法的引用赋值给一个变量,说明方法引用也是一种函数式接口的实现

3、默认方法

默认方法就是一个在接口里面有了一个有实现的方法。

1.8之前接口中的方法是不能有方法实现的,在1.8及以后打破了这个规则,一个接口,可以拥有默认方法,也可以拥有静态方法,并拥有他们的实现

类或者接口,去实现接口时,可以重写默认方法,这样做的原因说白了,其实也是为了Lambda表达式的使用

4、Stream API

新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。

何谓 函数式编程风格 ?

指令性语言 => 描述性语言
从手动处理数据 => 给我需要的数据

很直白的对比就是,java语言本身就是指令性语言,每一步操作,你都需要告诉虚拟机,虚拟机在和机器去做 “交涉”!而SQL语言是典型的描述性语言,sql他不需要关注这些数据的来源,以及怎么一步步“细化”处理(分组,条件过滤),我们写的sql本身表达的意思就是,我要一个什么条件的数据,然后,执行这个sql,数据就会按照你的条件返回。

而Stream API 就是描述性语言的体现,下面看个例子~

情景:获取班级男生中,分数最高前十名的平均年龄!

普通实现:
1、找出男生,filter(man)
2、分数倒排,sort(desc)
3、取前十名,limit(1-10)
4、获取年龄,get(age)
5、计算平均值,average()

以上步骤,我们是不是得写代码一步步的去实现?这就是所谓的指令性语言

而有了 Stream API 之后,我们可以这样做

//伪代码如下
List list = new ArrayList();
double ave = Arrays.stream(list)
        .filter()
        .sorted()
        .limit(10)
        .mapToDouble()
        .average().orElse(0);

是不是很像sql,我们需要是告诉一个“数据集合”我要什么样的数据,最后,他会把你想要的东西返回给你~

Stream和普通集合的区别?

  • stream不存储元素,只是提供了操作集合的各种方法
  • 适配函数式接口
  • 延迟计算
  • 链式调用,上面的各个链式调用方法,我们称为一个操作的话,在Steam中就有“中间操作”,和“终止操作”

我们找到源码,发现,前面的方法返回都还是一个Stream,也就是可以继续 点 下去,而average返回就已经不是Steam了


为什么不推荐用Stream操作原生数据类型?

  • 产生装箱,拆箱,影响性能
  • Stream不提供数值类型的特殊方法

常用方法

  • 遍历:forEach()、peek()、map(),三个方法都是遍历所有元素,中途无法优雅中止。(除非抛出异常,宕机等)
  • 去重:distinct(),去重后,保持 顺序稳定
  • 数据类型转换
    Stream stream = Arrays.stream(stu);
    List list = stream.collect(Collectors.toList());
    Set set = stream.collect(Collectors.toSet());
    Map map = stream.collect(Collectors.toMap(t -> t.getName(), t -> t));
    
    Student[] arr = stream.toArray(t -> new Student[t]);
    Student[] arr = stream.toArray(Student[]::new);
    
5、Date Time API

加强对日期与时间的处理。
Clock,LocalDate,LocalTime

6、Optional 类

Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
Optional是个容器,提供各种方法,获取内部是否有值,或执行各种快捷操作。
Optional.empty()返回一个空的Optional对象,对其执行的各种操作均为空操作,无任何效果

消除箭头代码的实例


Optional常用方法

7、并发集合,并行数组 8、JVM的改变

使用metaspace(JEP 122)代替持久代(PermGen space)。

在JVM参数方面:

使用-XX:metaSpaceSize和-XX:MaxmetaspaceSize代替原来的-XX:PermSize和-XX:MaxPermSize。

9、锁的优化
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/681950.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号