Java8到Java11新特性和用法介绍
Java8新特性概述
Java 8引入了许多令人兴奋的新特性。以下是一些Java 8的主要特性介绍:
-
Lambda表达式:Lambda表达式是Java 8最显著的特性之一。它们提供了一种简洁的语法来表示匿名函数,可以作为方法参数传递,使得代码更加简洁和易读。
-
函数式接口:Java 8引入了函数式接口的概念,它是只有一个抽象方法的接口。函数式接口可以与Lambda表达式一起使用,使得在Java中可以更方便地编写函数式编程风格的代码。
-
流(Stream):流是Java 8中新增的一种处理数据集合的抽象。流提供了一种类似于SQL查询的方式来操作集合,可以通过一系列的中间操作(如过滤、映射、排序等)和终端操作(如收集、聚合等)来处理数据。
-
方法引用:方法引用提供了一种更简洁的方式来调用已经存在的方法。通过使用双冒号(::)操作符,可以直接引用类的静态方法、实例方法或构造函数。
-
默认方法:Java 8允许在接口中定义默认方法。默认方法可以包含方法体实现,使得在接口中添加新方法时不会破坏已有的实现类。
-
Optional类:Optional类是Java 8为了解决空指针异常而引入的一种方式。它可以包装一个可能为空的值,并提供了一些方法来避免空指针异常的发生。
-
新的日期和时间API:Java 8引入了全新的日期和时间API,以替代旧的Date和Calendar类。新的API提供了更好的设计和易用性,同时也解决了旧API中一些常见的问题。
这些是Java 8引入的一些主要特性,它们在提供新功能的同时,也使得Java语言更加现代化和强大。
1.Lambda表达式用法
Lambda表达式是Java 8引入的一项重要特性,它提供了一种简洁的语法来表示匿名函数。Lambda表达式常用于函数式接口的实现,可以替代使用匿名内部类的方式。以下是一些Lambda表达式的用法示例:
- 使用Lambda表达式作为函数式接口的实现:
// 定义一个函数式接口
interface MyInterface {
void doSomething();
}
// 使用Lambda表达式实现接口
MyInterface myInterface = () -> {
// 在这里编写需要执行的代码块
System.out.println("Doing something...");
};
// 调用接口的方法
myInterface.doSomething();
- 使用Lambda表达式作为函数式接口的参数:
// 定义一个函数式接口
interface MyInterface {
void doSomething();
}
// 在方法中接受函数式接口作为参数
void performAction(MyInterface action) {
action.doSomething();
}
// 调用方法,传递Lambda表达式作为参数
performAction(() -> {
// 在这里编写需要执行的代码块
System.out.println("Doing something...");
});
- 使用Lambda表达式对集合进行操作:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 使用Lambda表达式遍历集合
names.forEach(name -> System.out.println(name));
// 使用Lambda表达式进行过滤
List<String> filteredNames = names.stream()
.filter(name -> name.length() > 4)
.collect(Collectors.toList());
// 使用Lambda表达式进行映射
List<Integer> nameLengths = names.stream()
.map(name -> name.length())
.collect(Collectors.toList());
以上示例展示了Lambda表达式在不同场景下的使用方式。通过Lambda表达式,可以以更简洁的方式编写代码,并提高代码的可读性和易维护性。
2.函数式接口用法
函数式接口是Java 8引入的一个概念,它是只有一个抽象方法的接口。函数式接口通常与Lambda表达式一起使用,可以使代码更具有函数式编程的特点。下面是函数式接口的用法介绍:
- 定义函数式接口:
@FunctionalInterface
interface MyFunctionalInterface {
void doSomething();
}
@FunctionalInterface
注解用于标记函数式接口,确保接口只有一个抽象方法。- 函数式接口中可以包含默认方法和静态方法,但只能有一个抽象方法。
- 使用函数式接口:
- 使用匿名内部类:
MyFunctionalInterface functionalInterface = new MyFunctionalInterface() {
@Override
public void doSomething() {
// 在这里编写需要执行的代码块
System.out.println("Doing something...");
}
};
- 使用Lambda表达式:
MyFunctionalInterface functionalInterface = () -> {
// 在这里编写需要执行的代码块
System.out.println("Doing something...");
};
- 函数式接口作为方法参数:
函数式接口的一个重要应用是作为方法参数,可以传递Lambda表达式作为实参。
void performAction(MyFunctionalInterface action) {
action.doSomething();
}
performAction(() -> {
// 在这里编写需要执行的代码块
System.out.println("Doing something...");
});
通过将函数式接口作为方法参数,可以实现灵活的行为传递,将具体的行为作为参数进行传递和执行。
- Java内置的函数式接口:
Java 8还提供了一些内置的函数式接口,位于java.util.function
包下,用于常见的函数式编程场景。例如:
Consumer<T>
:消费一个参数,无返回值。Supplier<T>
:提供一个值,无参数。Function<T, R>
:接受一个参数,返回一个结果。Predicate<T>
:接受一个参数,返回一个布尔值。
这些函数式接口可以直接使用,无需自定义,提供了丰富的函数式编程功能。
函数式接口与Lambda表达式的结合可以使代码更加简洁和易读,同时也支持函数式编程风格的代码编写。它们是Java 8中函数式编程特性的基础。
3.流(Stream)用法
流(Stream)是Java 8中引入的一种处理数据集合的抽象。流提供了一种类似于SQL查询的方式来操作集合,可以通过一系列的中间操作和终端操作来处理数据。以下是流的用法介绍:
- 创建流:
可以通过集合、数组、I/O通道等方式来创建流。
- 从集合创建流:
List<String> list = Arrays.asList("Alice", "Bob", "Charlie");
Stream<String> stream = list.stream();
- 从数组创建流:
String[] array = {"Alice", "Bob", "Charlie"};
Stream<String> stream = Arrays.stream(array);
- 从文件创建流:
Path path = Paths.get("file.txt");
Stream<String> stream = Files.lines(path);
- 中间操作:
中间操作是对流进行转换、过滤和映射等操作的步骤。它们可以按照需要链式调用,形成操作的流水线。
- 过滤操作:
Stream<String> filteredStream = stream.filter(name -> name.length() > 4);
- 映射操作:
Stream<Integer> lengthsStream = stream.map(name -> name.length());
- 排序操作:
Stream<String> sortedStream = stream.sorted();
- 去重操作:
Stream<String> distinctStream = stream.distinct();
- 终端操作:
终端操作是对流进行最终结果计算或收集的操作,它们会触发流的遍历和处理。
- 遍历输出:
stream.forEach(System.out::println);
- 收集操作:
List<String> collectedList = stream.collect(Collectors.toList());
- 匹配操作:
boolean anyMatch = stream.anyMatch(name -> name.startsWith("A"));
boolean allMatch = stream.allMatch(name -> name.length() > 3);
boolean noneMatch = stream.noneMatch(name -> name.endsWith("x"));
- 聚合操作:
Optional<String> firstElement = stream.findFirst();
Optional<String> anyElement = stream.findAny();
long count = stream.count();
流的中间操作和终端操作可以根据需要组合使用,形成复杂的数据处理流程。通过流,可以简化集合数据的处理,使代码更加简洁和易读。
需要注意的是,流的中间操作是惰性求值的,只有在终端操作触发时才会进行实际的计算和处理。这种延迟求值的机制可以提高效率,并允许对大型数据集进行高效的操作。
4.方法引用用法
方法引用是Java 8中引入的一种语法,用于直接引用已经存在的方法作为Lambda表达式的替代。它提供了一种更简洁的方式来调用已经定义的方法。方法引用可以分为以下几种情况:
- 静态方法引用:
可以直接引用已定义的静态方法。
// 静态方法
class MyClass {
static void myStaticMethod() {
System.out.println("Hello, World!");
}
}
// 静态方法引用
Runnable runnable = MyClass::myStaticMethod;
- 实例方法引用:
可以直接引用已定义的实例方法。
// 实例方法
class MyClass {
void myInstanceMethod() {
System.out.println("Hello, World!");
}
}
// 实例方法引用
MyClass myObject = new MyClass();
Runnable runnable = myObject::myInstanceMethod;
- 对象方法引用:
可以引用已定义的特定对象的实例方法。
// 实例方法
class MyClass {
void myInstanceMethod() {
System.out.println("Hello, World!");
}
}
// 对象方法引用
MyClass myObject = new MyClass();
Consumer<MyClass> consumer = MyClass::myInstanceMethod;
consumer.accept(myObject);
- 构造函数引用:
可以引用已定义的构造函数。
// 构造函数
class MyClass {
MyClass() {
System.out.println("Creating MyClass object");
}
}
// 构造函数引用
Supplier<MyClass> supplier = MyClass::new;
MyClass myObject = supplier.get();
在方法引用中,使用::
操作符来引用已存在的方法或构造函数。根据引用的方法类型不同,可以选择合适的函数式接口来匹配方法引用。方法引用提供了一种更简洁、更易读的方式来使用已存在的方法,使代码更加简洁和精炼。
5.默认方法用法
默认方法是Java 8引入的一种特性,它允许在接口中定义具有默认实现的方法。默认方法的目的是在不破坏现有实现类的情况下,向接口添加新的方法。以下是默认方法的用法介绍:
- 定义默认方法:
默认方法使用default
关键字在接口中进行定义,并提供默认的方法实现。
interface MyInterface {
void myAbstractMethod();
default void myDefaultMethod() {
// 默认方法的实现
System.out.println("Default method");
}
}
- 实现接口:
实现接口时,可以选择是否重写默认方法。如果实现类选择不重写默认方法,将直接继承接口中提供的默认实现。
class MyClass implements MyInterface {
@Override
public void myAbstractMethod() {
// 实现抽象方法的具体逻辑
System.out.println("Abstract method implementation");
}
}
- 调用默认方法:
默认方法可以通过实现类的实例直接调用,也可以通过接口的引用调用。
MyClass myObject = new MyClass();
myObject.myAbstractMethod(); // 调用抽象方法
myObject.myDefaultMethod(); // 调用默认方法
MyInterface myInterface = new MyClass();
myInterface.myAbstractMethod(); // 调用抽象方法
myInterface.myDefaultMethod(); // 调用默认方法
需要注意的是,如果一个类实现了多个接口,并且这些接口具有相同的默认方法,那么实现类必须重写该方法并提供自己的实现,否则会导致编译错误。在这种情况下,可以使用InterfaceName.super.methodName()
的方式调用指定接口的默认方法。
默认方法的引入使得在接口中添加新方法时,不会破坏已有的实现类,同时也避免了创建大量的适配类。默认方法为Java的接口增加了更多的灵活性和可扩展性。
6.Optional类用法
Optional类是Java 8中引入的一个用于处理可能为null的值的容器类。它提供了一种更安全和优雅的方式来处理可能存在空值的情况。以下是Optional类的用法介绍:
- 创建Optional对象:
可以使用Optional.of()
、Optional.ofNullable()
和Optional.empty()
方法来创建Optional对象。
Optional.of(value)
:创建一个非空的Optional对象,如果value为null,则抛出NullPointerException。
Optional<String> optional1 = Optional.of("Hello");
Optional.ofNullable(value)
:创建一个Optional对象,如果value为null,则创建一个空的Optional对象。
String str = null;
Optional<String> optional2 = Optional.ofNullable(str);
Optional.empty()
:创建一个空的Optional对象。
Optional<String> optional3 = Optional.empty();
- 判断Optional是否包含值:
可以使用isPresent()
方法来判断Optional对象是否包含值。
Optional<String> optional = Optional.of("Hello");
if (optional.isPresent()) {
System.out.println("Optional contains a value");
} else {
System.out.println("Optional is empty");
}
- 获取Optional中的值:
可以使用get()
方法来获取Optional对象中的值。需要注意的是,如果Optional对象为空,则调用get()
方法会抛出NoSuchElementException。
Optional<String> optional = Optional.of("Hello");
String value = optional.get();
System.out.println(value);
- 使用默认值:
可以使用orElse()
方法来获取Optional对象中的值,如果Optional为空,则返回指定的默认值。
Optional<String> optional = Optional.empty();
String value = optional.orElse("Default Value");
System.out.println(value);
- 条件判断:
可以使用ifPresent()
方法来进行条件判断,如果Optional对象包含值,则执行指定的操作。
Optional<String> optional = Optional.of("Hello");
optional.ifPresent(val -> System.out.println("Value: " + val));
- 转换值:
可以使用map()
方法对Optional对象中的值进行转换,并返回一个新的Optional对象。
Optional<String> optional = Optional.of("Hello");
Optional<Integer> lengthOptional = optional.map(val -> val.length());
- 过滤值:
可以使用filter()
方法对Optional对象中的值进行过滤,并返回一个新的Optional对象。
Optional<String> optional = Optional.of("Hello");
Optional<String> filteredOptional = optional.filter(val -> val.length() > 5);
Optional类提供了一种更加优雅和安全的方式来处理可能存在空值的情况。它可以避免在使用null值时产生NullPointerException,并提供了丰富的方法来处理Optional对象中的值。通过合理使用Optional类,可以使代码更加健壮和可靠。
7.新的日期和时间API用法
Java 8引入了新的日期和时间API(java.time包),用于替代旧的Date和Calendar类,提供了更简单、更安全、更易用的日期和时间处理方式。以下是新的日期和时间API的用法介绍:
- 创建日期和时间对象:
可以使用LocalDate
、LocalTime
和LocalDateTime
类来创建日期和时间对象。
LocalDate
:表示日期,例如年、月、日。
LocalDate date = LocalDate.now(); // 当前日期
LocalDate specificDate = LocalDate.of(2022, 5, 31); // 指定日期
LocalTime
:表示时间,例如小时、分钟、秒。
LocalTime time = LocalTime.now(); // 当前时间
LocalTime specificTime = LocalTime.of(12, 30, 45); // 指定时间
LocalDateTime
:表示日期和时间的组合。
LocalDateTime dateTime = LocalDateTime.now(); // 当前日期和时间
LocalDateTime specificDateTime = LocalDateTime.of(2022, 5, 31, 12, 30, 45); // 指定日期和时间
- 格式化和解析日期和时间:
可以使用DateTimeFormatter
类来格式化和解析日期和时间。
LocalDateTime dateTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = dateTime.format(formatter); // 格式化为字符串
System.out.println(formattedDateTime);
String dateString = "2022-05-31";
LocalDate parsedDate = LocalDate.parse(dateString, formatter); // 解析字符串为日期对象
System.out.println(parsedDate);
- 日期和时间的计算和调整:
可以使用各种方法来进行日期和时间的计算和调整。
plusXxx()
方法:增加指定的时间量。
LocalDateTime dateTime = LocalDateTime.now();
LocalDateTime newDateTime = dateTime.plusDays(7).plusHours(3);
minusXxx()
方法:减少指定的时间量。
LocalDate date = LocalDate.now();
LocalDate newDate = date.minusWeeks(1).minusDays(3);
withXxx()
方法:调整日期或时间的指定部分。
LocalDateTime dateTime = LocalDateTime.now();
LocalDateTime newDateTime = dateTime.withDayOfMonth(15).withHour(10);
- 比较和判断日期和时间:
可以使用isBefore()
、isAfter()
和isEqual()
等方法来比较和判断日期和时间的关系。
LocalDate date1 = LocalDate.of(2022, 5, 31);
LocalDate date2 = LocalDate.of(2023, 1, 1);
boolean isBefore = date1.isBefore(date2);
boolean isAfter = date1.isAfter(date2);
boolean isEqual = date1.isEqual(date2);
- 时区和偏移:
可以使用ZoneId
和ZoneOffset
类来表示时区和偏移。
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZoneOffset zoneOffset = ZoneOffset.ofHours(8);
- 日期和时间的转换:
可以使用atZone()
方法将日期和时间
Java9新特性概述
Java 9于2017年发布,引入了一些重要的新特性和改进。以下是Java 9的一些主要新特性:
-
模块化系统(Java Platform Module System,简称JPMS):
Java 9引入了模块化系统,允许将代码和依赖项组织为模块,以提供更好的封装和可重用性。模块化系统通过模块描述文件(module-info.java)来定义模块,并引入了模块路径来管理模块之间的依赖关系。 -
JShell(交互式Java Shell):
JShell是一个交互式的命令行工具,允许开发者在不编写完整的Java类的情况下进行实时的Java代码交互和测试。它提供了一个类似于REPL(Read-Eval-Print Loop)的环境,可以即时执行代码片段并查看结果。 -
改进的Java编译器:
Java 9引入了一些编译器的改进,如增量编译(Incremental Compilation)和改进的编译器接口(Compiler API),提升了编译速度和效率。 -
改进的Java集合库:
Java 9对集合库进行了一些改进,包括添加了一些新的集合类和接口,如List.of()
、Set.of()
、Map.of()
等静态工厂方法,用于创建不可变集合。 -
改进的Stream API:
Java 9对Stream API进行了一些改进,包括添加了一些新的方法,如takeWhile()
和dropWhile()
,用于在满足指定条件的情况下截取或丢弃元素。 -
多版本兼容的JAR文件:
Java 9允许在一个JAR文件中包含多个版本的类文件,以便在不同的Java版本中使用适当的类文件。 -
改进的安全性:
Java 9在安全性方面进行了一些改进,包括增强了加密算法、禁用了一些不安全的算法和协议,以及改进了安全管理器等。
除了上述的主要特性之外,Java 9还包含了一些其他改进,如改进的性能、改进的垃圾回收器、新的JavaDoc工具等。总体而言,Java 9引入了一些重要的特性和改进,旨在提升开发者的效率、增强安全性,并改善性能和可维护性。
Java10新特性概述
Java 10于2018年发布,引入了一些新的特性和改进。以下是Java 10的一些主要新特性:
-
局部变量类型推断(var关键字):
Java 10引入了局部变量类型推断,允许在局部变量的声明中使用var关键字来推断变量的类型。这使得代码更加简洁,减少了冗余的类型声明。 -
应用程序类数据共享(Application Class-Data Sharing):
Java 10引入了应用程序类数据共享(AppCDS),允许多个Java虚拟机实例共享已预先编译的类数据。这提供了更快的应用程序启动时间和减少内存占用。 -
垃圾回收器接口:
Java 10引入了一种新的垃圾回收器接口,允许开发者实现自定义的垃圾回收器。这提供了更大的灵活性和可扩展性。 -
并行全垃圾收集器(Parallel Full GC):
Java 10改进了垃圾回收器,引入了并行全垃圾收集器(Parallel Full GC),用于提升全垃圾收集(Full GC)的性能。 -
改进的线程局部变量(Thread-Local Handshakes):
Java 10引入了线程局部变量握手机制(Thread-Local Handshakes),可以在不停止其他线程的情况下与特定线程进行握手,以便更有效地进行协作和优化。 -
可选择的GC日志文件:
Java 10改进了GC日志文件格式,引入了可选择的GC日志文件,提供了更灵活和可读性更强的选项。 -
改进的堆内存分配:
Java 10改进了堆内存分配,引入了一种新的内存分配策略,以提高分配速度和减少内存开销。 -
其他改进:
Java 10还包括一些其他改进,如改进的本地内存(Native Memory Tracking)、改进的时间API等。
请注意,这只是Java 10的一些主要特性和改进。Java平台持续发展,每个版本都带来了新的功能和改进,以提升开发者的体验和应用程序的性能。
Java11新特性概述
Java 11是在2018年发布的Java平台的版本,它引入了一些新的特性和改进。以下是Java 11的一些主要新特性:
- 局部变量类型推断的增强:
Java 10中引入了局部变量类型推断(var关键字),Java 11进一步增强了这个特性,允许在Lambda表达式的参数上使用var。
(var x, var y) -> x.process(y)
- 字符串新增方法:
String类中新增了一些方便的方法,如isBlank()
用于判断字符串是否为空或仅包含空白字符,lines()
用于将字符串拆分成行,并返回一个流。
String str = " Hello, World! ";
boolean isBlank = str.isBlank();
Stream<String> lines = str.lines();
- 新增标准HTTP客户端:
Java 11中引入了一个新的标准HTTP客户端API,替代了过时的HttpURLConnection
类。新的HTTP客户端提供了更简洁、易用和灵活的方式来进行HTTP通信。
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://example.com"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
String responseBody = response.body();
- 升级的垃圾回收器:
Java 11中引入了一个新的垃圾回收器(Epsilon GC),该回收器主要用于性能测试和性能调优,不执行实际的垃圾回收操作。
java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC MainClass
- ZGC垃圾回收器的稳定版发布:
Java 11中,ZGC垃圾回收器由实验性功能转为稳定版,它是一种低延迟的垃圾回收器,适用于大内存应用程序。
java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC MainClass
除了上述的主要特性之外,Java 11还包含了一些其他改进,如支持动态类文件常量、启用HTTP/2、改进的安全性和性能优化等。总体而言,Java 11提供了一些有用的新特性和改进,旨在提升开发人员的效率和应用程序的性能。