当前位置: 首页 > article >正文

Java8的新特性

1.Lambda表达式和函数式接口

Lambda的基础:函数式接口

Java 8与之前版本的区别:

  • Java 7及之前:接口中只能包含抽象方法,无法通过函数式接口简洁地表示Lambda表达式。
  • Java 8:通过@FunctionalInterface注解,明确表示接口为函数式接口,允许传递Lambda表达式作为参数。

函数式接口是只有一个抽象方法的接口。 这里的重点是"只有一个"和"抽象方法"。

只有一个: 这意味着接口中不能有多个抽象方法。如果一个接口有多个抽象方法,那么Lambda表达式就无法确定它应该实现哪个方法了。
抽象方法: 这意味着这个方法没有具体的实现(没有方法体)。接口中的默认方法(default methods)和静态方法(static methods)不属于抽象方法,它们都有具体的实现。

Java 8引入了一个特殊的注解:@FunctionalInterface。这个注解用于标记一个接口是函数式接口。虽然这个注解不是必需的(即使没有这个注解,只要接口满足函数式接口的定义,它仍然是函数式接口),但建议使用它。因为@FunctionalInterface注解有两个好处:

明确性: 它可以清楚地表明这个接口是一个函数式接口,方便其他开发者理解。
编译时检查:
如果你在一个标记了@FunctionalInterface的接口中添加了多个抽象方法,编译器会报错,帮助你避免错误。

Lambda表达式

Java 8与之前版本的区别:
  • Java 7及之前:行为的传递通常依赖于匿名类,代码较为冗长。
  • Java 8:Lambda表达式简化了代码结构,避免了匿名类的冗余代码。

Lambda表达式提供了一种更加简洁,更加优雅的方式表示可传递的代码块

Lambda表达式本质上就是一个匿名函数。 它可以像普通函数一样接受参数、执行代码,并返回值。但与普通函数不同的是,Lambda表达式没有名称

Lambda表达式的语法

( parameter-list ) -> { expression-or-statements }

一个Lambda表达式由以下几个部分组成:

参数列表:() 中的parameter-list是以逗号分隔的参数。Java 11 后,还可以使用 var 关键字作为参数类型,有点 JavaScript 的味道 。Lambda表达式可以有零个或多个参数。参数的类型可以显式声明,也可以由编译器根据上下文推断。
箭头符号(->): 箭头符号将参数列表与Lambda表达式的主体分隔开。
函数体: {} 中的 expression-or-statements 为 Lambda 的主体。函数体包含Lambda表达式要执行的代码。它可以是一个表达式,也可以是一个代码块。

  • 如果函数体是一个表达式,Lambda表达式会隐式地返回这个表达式的值。
  • 如果函数体是一个代码块,则需要使用return语句来返回值(或者没有返回值,就像void方法一样)。

Lambda表达式与函数式接口的关系:Lambda表达式可以用在任何需要函数式接口的地方。因为Lambda表达式本质上就是函数式接口的一个实例。当你写下一个Lambda表达式时,你实际上是在创建一个实现了函数式接口的匿名对象。Lambda表达式的类型就是它所实现的函数式接口的类型。

2.Steam API

在Java中,Steam流是一种强大的数据处理工具,它允许我们对集合进行各种操作,如筛选、过滤、映射、分组等。这些操作可能是中间操作,返回一个Steam流,也可能是终端操作,返回一个结果。

Java 8与之前版本的区别:

  • Java 7及之前:集合操作通常是通过循环遍历来实现,代码繁琐,缺乏可读性。
  • Java 8:通过Stream API提供了更加简洁、功能强大的数据操作方法,可以通过链式调用实现复杂的操作。(filter方法)

Steam流的优势

Steam流的操作不会影响原始集合,也不会存储数据。这意味着我们可以在不改变原始数据的情况下对数据进行处理。在传统的集合操作中,我们通常需要将数据复制到另一个集合中,这可能会导致额外的内存开销。而Steam流则将集合中的元素逐个复制到一个流动的容器中进行操作,操作结束后,容器消失,不会产生额外的内存占用。
Steam流支持同步和并发执行。如果我们直接获取Steam流,得到的是同步执行的Steam流。如果我们调用parallelStream()方法,则得到一个可以并发执行的Steam流。这使得我们可以充分利用多核处理器的性能,加快数据处理速度。

3.默认方法

Java 8允许在接口中定义默认方法,避免了接口修改时需要修改所有实现类的问题。默认方法具有默认实现,可以由接口实现类继承或重写。通过使用default关键字,可以在接口中定义具有默认实现非抽象的方法(扩展方法),而不破坏实现了该接口的类的代码。允许在已有的接口中添加新方法,而同时又保持了与旧版本代码的兼容性。类似于继承父类,重写父类的方法

Java 8与之前版本的区别:

  • Java 7及之前:接口无法包含实现,若需要添加新方法,必须修改实现类。
  • Java 8:接口可以包含默认实现的方法,接口的变更不会影响已有的实现类。

4.方法引用

方法引用是Lambda表达式的一种更加简洁的形式,可以直接引用已有的Java类或对象(实例)的方法或构造器。主要使用 ::操作符,方法引用

第一种方法引用是构造器引用,它的语法是Class::new,或者更一般的Class< T >::new。请注意构造器没有参数。   

final Car car = Car.create( Car::new );

final List< Car > cars = Arrays.asList( car ); 

第二种方法引用是静态方法引用,它的语法是Class::static_method。请注意这个方法接受一个Car类型的参数

  cars.forEach( Car::collide );

第三种方法引用是特定类的任意对象的方法引用,它的语法是Class::method。请注意,这个方法没有参数。

cars.forEach( Car::repair );

第四种方法引用是特定对象的方法引用,它的语法是instance::method。请注意,这个方法接受一个Car类型的参数 

final Car police = Car.create( Car::new );

cars.forEach( police::follow );

5.重复注解

自从Java5引入了注解机制,这一特性就变得非常流行并且广为使用。然而,使用注解的一个限制是相同的注解在同一位置只能声明一次,不能声明多次。Java8打破了这条规则,引入了重复注解机制,这样相同的注解可以在同一地方声明多次。

重复注解机制本身必须用@Repeatable注解。事实上,这并不是语言层面上的改变,更多的是编译器的技巧,底层的原理保持不变。

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 定义重复注解类型
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Repeatable(Authors.class)
@interface Author {
    String name();
}

// 定义容器注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Authors {
    Author[] value();
}

// 使用重复注解
@Author(name = "John")
@Author(name = "Jane")
class Book {
    // 类的内容
}

@Repeatable 注解是 Java 8 引入的,它的作用是指定存储重复注解的容器注解。在上述代码中,@Author 注解被标记为可重复的,其容器注解是 @Authors。
@Retention(RetentionPolicy.RUNTIME) 表示注解在运行时可见,这样可以通过反射机制获取注解信息。
@Target(ElementType.TYPE) 表示注解可以应用于类、接口、枚举等类型上。

重复注解的实现

1.需要定义一个正常的注解类型,该注解将被重复使用。同时,还需要定义一个容器注解,容器注解用于存储重复注解的数组。

2.在需要的地方多次使用定义好的重复注解。

3.使用反射机制可以获取类上的重复注解信息。getAnnotationsByType 方法是 Java 8 为了方便获取重复注解而引入的,它可以直接返回指定类型的所有重复注解数组。

import java.lang.reflect.AnnotatedElement;

public class Main {
    public static void main(String[] args) {
        // 获取 Book 类的 Class 对象
        Class<Book> bookClass = Book.class;
        // 获取类上的所有 @Author 注解
        Author[] authors = bookClass.getAnnotationsByType(Author.class);

        // 遍历注解数组并输出信息
        for (Author author : authors) {
            System.out.println("Author: " + author.name());
        }
    }
}

6.Optional类

Optional类主要是针对空指针异常的问题,Optional实际上是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

Optional optional = Optional.ofNullable(null);
System.out.println(optional.isPresent());
System.out.println(optional.orElse(0));//当值为空时给与初始值
System.out.println(optional.orElseGet(() -> new String[]{"a"}));

如果Optional类的实例为非空值的话,isPresent0返回true,否从返回false。

为了防止Optional为空值,orElseGet0方法通过回调函数来产生一个默认值。map()函数对当前Optional的值进行转化,然后返回一个新的Optional实例。orElse0方法和orElseGet0方法类似,但是orElse接受一个默认值而不是一个回调函数。

7.Date/Time API

在旧版的 Java 中,日期时间 API 存在诸多问题,比如:

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

        2.设计很差 − Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。

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

新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。在设计新版API时,十分注重与旧版API的兼容性:不允许有任何的改变(从java.util.Calendar中得到的深刻教训l)。

让我们用例子来看一下新版API主要类的使用方法。

  • Clock类:通过指定一个时区,然后就可以获取到当前的时刻,日期与时间。Clock可以替换System.currentTimeMillis0与TimeZone.getDefault0。
  • LocaleDate类:只持有ISO-8601格式且无时区信息的日期部分。
  • LocaleTime类:只持有ISO-8601格式且无时区信息的时间部分。
  • Duration类:在秒与纳秒级别上的一段时间。Duration使计算两个日期间的不同变的十分简单。


http://www.kler.cn/a/585143.html

相关文章:

  • mov格式视频如何转换mp4?
  • C++ 左值(lvalue)和右值(rvalue)
  • DSTTN
  • Kafka×DeepSeek:智能决策破取经八十一难!
  • 批量压缩与优化 Excel 文档,减少 Excel 文档大小
  • 嵌入式八股ARM篇
  • MyBatis·下
  • AGI大模型(3):大模型生成内容
  • Vi/Vim命令详解:高效文本编辑的利器
  • C语言【数据结构】:理解什么是数据结构和算法(启航)
  • 51c大模型~合集7
  • 架构师论文《论云原生架构及其应用》
  • G-Star 公益行起航,挥动开源技术点亮公益!
  • C#中通过Response.Headers设置自定义参数
  • 万字讲清大模型的发展,按时间排序(1950年到2025年)
  • Python - 爬虫;爬虫-网页抓取数据-工具curl
  • 银河麒麟V10ServerSP3中Redis7源码编译与安装详细教程
  • SpringDataRedis存储Redis的数据序列化
  • 【C++标准库类型】深入理解string类型:从基础到实践
  • 【VSCODE 插件 可视化】:SVG 编辑插件 SVG Editor