首页 > 其他分享 >JDK8-17期间增加的新特性

JDK8-17期间增加的新特性

时间:2024-08-15 16:07:51浏览次数:7  
标签:Java String 17 System 特性 JDK8 println java out

JDK新特性

1.Lambda表达式

在Java中,Lambda表达式是一种简洁的表示匿名函数的方法。它们提供了一种方式来传递代码作为数据,这在实现某些接口(特别是那些只包含一个抽象方法的接口,即函数式接口)时特别有用。Lambda表达式使得代码更加简洁,并提高了可读性。

1.1.基本语法

Java中Lambda表达式的基本语法如下:

java复制代码

(参数列表) -> { Lambda体 }

或者,如果Lambda体只包含一个表达式(且该表达式的计算结果会自动返回),则可以省略大括号{}return关键字:

java复制代码

(参数列表) -> 表达式
  • 参数列表:Lambda表达式的参数,其类型可以显式声明,也可以由编译器自动推断。如果Lambda表达式只有一个参数,则圆括号()可以省略(但在某些情况下,为了清晰起见,最好保留它们)。
  • ->:Lambda操作符,用于分隔参数列表和Lambda体。
  • Lambda体:包含Lambda表达式要执行的代码。如果代码只有一行,则可以省略大括号{};如果有多行代码,则需要使用大括号{}包围起来,并且可以通过return语句来返回值(如果Lambda表达式的返回类型不是void)。

1.2.示例

假设我们有一个函数式接口Greeting,它包含一个方法greet,该方法接受一个String参数并返回一个String

@FunctionalInterface  
interface Greeting {  
    String greet(String name);  
}  
  
public class LambdaExample {  
    public static void main(String[] args) {  
        Greeting greeting = name -> "Hello, " + name + "!";  
          
        String greetingMessage = greeting.greet("Alice");  
        System.out.println(greetingMessage);  // 输出: Hello, Alice!  
    }  
}

在上面的示例中创建了一个Greeting接口的匿名实现,并直接将其赋值给Greeting类型的变量greeting。这个匿名实现使用了一个Lambda表达式,它接受一个名为name的参数,并返回一个包含问候语的字符串。

1.3.在Java集合框架中的使用

Lambda表达式在Java集合框架(如ListSetMap的接口及其实现类)中特别有用,因为Java 8引入了许多新的默认方法和静态方法,这些方法接受函数式接口作为参数,允许你以声明性方式处理集合。

例如,使用List接口的forEach方法遍历列表:

List<String> list = Arrays.asList("apple", "banana", "cherry");  
list.forEach(s -> System.out.println(s));

或者使用Stream API对集合进行更复杂的操作:

List<String> filteredList = list.stream()  
    .filter(s -> s.startsWith("a"))  
    .collect(Collectors.toList());  
System.out.println(filteredList);  // 输出: [apple, banana]

在这个例子中,我们使用了Stream API的filter方法来过滤出以字母"a"开头的字符串,并使用collect方法将结果收集到一个新的列表中。Lambda表达式s -> s.startsWith("a")作为filter方法的参数,定义了过滤条件。

2.新的日期/时间API的使用

Java 8(也称为JDK 1.8)引入了全新的日期和时间API,旨在解决旧的java.util.Datejava.util.Calendar类中存在的许多问题,如设计缺陷、易用性差和时区处理复杂等。新的日期/时间API位于java.time包及其子包中,提供了一套全面、强大且易于使用的日期和时间类。

1.1.主要类

  • LocalDate:表示一个具体的日期,不包含时间信息,也不包含时区信息。
  • LocalTime:表示一个具体的时间,不包含日期信息,也不包含时区信息。
  • LocalDateTime:表示一个具体的日期和时间,不包含时区信息。
  • ZonedDateTime:表示一个具体的日期、时间和时区。
  • Instant:表示时间线上的一个瞬时点,可以精确到纳秒。它通常用于表示UTC时间。
  • Duration:表示两个时间点之间的时间量,以秒和纳秒为单位。
  • Period:表示两个日期之间的时间量,以年、月和日为单位。
  • DateTimeFormatter:用于格式化和解析日期-时间对象的类。

1.2.示例

1.2.1.创建日期和时间

import java.time.LocalDate;  
import java.time.LocalTime;  
import java.time.LocalDateTime;  
import java.time.ZonedDateTime;  
  
public class NewDateTimeAPIExample {  
    public static void main(String[] args) {  
        // LocalDate  
        LocalDate date = LocalDate.of(2023, 10, 1);  
        System.out.println("Date: " + date);  
  
        // LocalTime  
        LocalTime time = LocalTime.of(14, 30);  
        System.out.println("Time: " + time);  
  
        // LocalDateTime  
        LocalDateTime dateTime = LocalDateTime.of(2023, 10, 1, 14, 30);  
        System.out.println("Date-Time: " + dateTime);  
  
        // ZonedDateTime  
        ZonedDateTime zonedDateTime = dateTime.atZone(ZoneId.of("Europe/Paris"));  
        System.out.println("Zoned Date-Time: " + zonedDateTime);  
    }  
}

1.2.2.格式化日期和时间

import java.time.LocalDateTime;  
import java.time.format.DateTimeFormatter;  
  
public class DateTimeFormatterExample {  
    public static void main(String[] args) {  
        LocalDateTime dateTime = LocalDateTime.now();  
  
        // 自定义格式化  
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");  
        String formattedDateTime = dateTime.format(formatter);  
        System.out.println("Formatted Date-Time: " + formattedDateTime);  
  
        // 使用预定义的格式化  
        String isoDateTime = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);  
        System.out.println("ISO Formatted Date-Time: " + isoDateTime);  
    }  
}

1.2.3.解析字符串为日期和时间

import java.time.LocalDateTime;  
import java.time.format.DateTimeFormatter;  
  
public class ParseDateTimeExample {  
    public static void main(String[] args) {  
        String dateTimeStr = "2023-10-01 14:30:00";  
  
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");  
        LocalDateTime dateTime = LocalDateTime.parse(dateTimeStr, formatter);  
  
        System.out.println("Parsed Date-Time: " + dateTime);  
    }  
}

3.Optional类的使用

Optional 类是 Java 8 引入的一个容器类,它可以包含也可以不包含非空的值。使用 Optional 类可以避免显式的 null 检查,从而使代码更加简洁,并且可以减少 NullPointerException 的风险。

3.1.主要方法和使用场景

3.1.1.创建 Optional 对象

  • Optional.of(T value):创建一个 Optional 实例,该实例包含指定的非空值。如果 valuenull,则抛出 NullPointerException
  • Optional.ofNullable(T value):如果 value 不为 null,则创建一个包含 valueOptional 实例,否则创建一个空的 Optional 实例。
  • Optional.empty():创建一个空的 Optional 实例。

3.1.2.获取 Optional 中的值

  • T get():如果值存在,则返回该值,否则抛出 NoSuchElementException
  • boolean isPresent():如果值存在,则返回 true,否则返回 false
  • T orElse(T other):如果值存在,则返回该值,否则返回 other
  • T orElseGet(Supplier<? extends T> other):如果值存在,则返回该值,否则返回 other 生成的值。
  • T orElseThrow(Supplier<? extends X> exceptionSupplier):如果值存在,则返回该值,否则抛出 exceptionSupplier 生成的异常。

3.1.3.其他常用方法

  • Optional<U> map(Function<? super T, ? extends U> mapper):如果值存在,则对其应用给定的函数,并返回一个新的 Optional 结果。
  • Optional<T> filter(Predicate<? super T> predicate):如果值存在,并且满足给定的谓词,则返回包含该值的 Optional,否则返回一个空的 Optional

3.2.示例

import java.util.Optional;  
  
public class OptionalExample {  
    public static void main(String[] args) {  
        // 创建一个包含非空值的Optional  
        Optional<String> optionalName = Optional.of("Alice");  
  
        // 使用isPresent()检查值是否存在  
        if (optionalName.isPresent()) {  
            System.out.println(optionalName.get());  
        }  
  
        // 使用orElse()提供默认值  
        String nameOrDefault = optionalName.orElse("Unknown");  
        System.out.println(nameOrDefault); // 输出: Alice  
  
        // 使用map()转换值  
        Optional<Integer> optionalLength = optionalName.map(String::length);  
        System.out.println(optionalLength.orElse(0)); // 输出: 5  
  
        // 创建一个可能为空的Optional  
        Optional<String> optionalMaybeName = Optional.ofNullable(null);  
  
        // 使用orElseGet()提供默认值(通过方法调用)  
        String nameFromSupplier = optionalMaybeName.orElseGet(() -> "Default Name");  
        System.out.println(nameFromSupplier); // 输出: Default Name  
  
        // 使用filter()进行条件检查  
        Optional<String> filteredName = optionalName.filter(name -> name.startsWith("A"));  
        System.out.println(filteredName.orElse("Name does not start with A")); // 输出: Alice  
    }  
}

3.3.注意事项

  • 尽管 Optional 可以帮助减少 null 检查,但过度使用或误用(如在字段、返回类型或方法参数中)可能会使代码更加复杂,降低可读性。
  • 在处理可能为 null 的返回值时,Optional 是一个很好的选择,但在编写你自己的代码时,最好通过设计避免 null 值,或者至少限制它们的传播。
  • 使用 Optional 时,建议优先考虑使用 ifPresent()orElse()orElseGet()orElseThrow() 等方法,而不是直接调用 get() 方法,以避免 NoSuchElementException

4.接口增强

在Java中,接口(Interface)是一种引用类型,是一种抽象的类型,用于指定一组方法规范,但不提供这些方法的具体实现。从Java 8开始,接口得到了显著的增强,引入了默认方法(Default Methods)和静态方法(Static Methods),以及从Java 9开始引入的私有方法(Private Methods,包括私有实例方法和私有静态方法)。这些增强使得接口更加灵活和强大,同时也为Java的API设计提供了更多的可能性。

4.1. 默认方法(Default Methods)

在Java 8之前,接口中的所有方法都是抽象的,即它们没有实现体。Java 8引入了默认方法的概念,允许接口包含具有实现的方法。这意呀着,即使一个类没有显式地实现接口中的某个方法,它仍然可以被认为是该接口的实现,因为接口已经为该方法提供了默认实现。

默认方法使用default关键字来声明。

public interface MyInterface {  
    default void defaultMethod() {  
        System.out.println("This is a default method.");  
    }  
}

4.2. 静态方法(Static Methods)

静态方法也是Java 8引入的接口增强之一。与默认方法不同,静态方法不能被接口的实现类继承或重写。静态方法可以直接通过接口名来调用,而不需要接口的实例。

静态方法使用static关键字来声明。

public interface MyInterface {  
    static void staticMethod() {  
        System.out.println("This is a static method.");  
    }  
}

4.3. 私有方法(Private Methods,Java 9+)

从Java 9开始,接口中可以包含私有方法,包括私有实例方法和私有静态方法。私有方法主要用于辅助默认方法和静态方法的实现,使得接口内部的代码更加模块化和可重用。

私有实例方法使用private关键字声明,并且可以通过默认方法或另一个私有实例方法调用。

私有静态方法也使用private关键字声明,并且可以通过接口中的其他静态方法或私有静态方法调用。

public interface MyInterface {  
    default void defaultMethod() {  
        helperMethod();  
    }  
  
    private void helperMethod() {  
        System.out.println("This is a private method.");  
    }  
  
    static void staticMethod() {  
        helperStaticMethod();  
    }  
  
    private static void helperStaticMethod() {  
        System.out.println("This is a private static method.");  
    }  
}

4.4.总结

Java接口的这些增强使得接口不再仅仅是方法的声明集合,而是可以包含具体实现(默认方法)、静态工具方法(静态方法)以及辅助实现的私有方法。这些特性极大地提高了Java API的灵活性和表达能力,同时也为Java的面向对象编程带来了更多的可能性。

5.局部变量类型推断

在Java中,从Java 10开始引入了一种新的局部变量类型推断功能,称为局部变量类型推断(Local Variable Type Inference),主要通过var关键字来实现。这一特性使得开发者在声明局部变量时不必显式地指定变量的类型,编译器会自动根据变量初始化的表达式来推断其类型。

5.1.使用var关键字

使用var作为类型声明时,变量必须被初始化,因为编译器需要通过初始化表达式来推断变量的类型。一旦变量被声明并初始化,它就像被显式指定了类型的变量一样,可以进行后续的操作和赋值(但赋值时类型必须兼容)。

5.2.示例

var list = new ArrayList<String>(); // 编译器推断出list的类型为ArrayList<String>  
list.add("Hello");  
System.out.println(list.get(0));  
  
var number = 10; // 编译器推断出number的类型为int  
number = 20; // 正确,因为赋值类型是兼容的  
// number = "Hello"; // 错误,因为类型不兼容  
  
var stream = Stream.of("Java", "is", "cool"); // 编译器推断出stream的类型为Stream<String>  
stream.forEach(System.out::println);

5.3.注意事项

  • var只能用于局部变量,不能用于成员变量、方法参数、返回类型、捕获类型等。
  • 使用var可以提高代码的可读性和编写效率,但也可能使代码的类型信息不那么明显,因此建议在类型明确且代码简短时使用。
  • 在使用var时,如果初始化表达式比较复杂或难以一眼看出其类型,那么使用var可能会降低代码的可读性。
  • var类型推断是在编译时进行的,不会引入任何运行时成本。

5.4.总结

局部变量类型推断是Java 10引入的一个重要特性,通过var关键字简化了局部变量的声明,提高了代码编写的灵活性和效率。然而,在使用时也需要注意其对代码可读性的影响,并遵循最佳实践来合理使用。

6.switch表达式增强

Java中的switch表达式增强是Java语言在近年来进行的一项重要改进,旨在提供更简洁、灵活和强大的分支控制结构。这一特性在Java 12中首次作为预览特性引入,并在后续版本中逐步完善,最终在Java 14中成为标准特性。以下是关于Java中switch表达式增强的详细介绍:

6.1.基本语法

增强的switch表达式使用箭头(->)操作符替代了传统的case关键字,并引入了yield关键字用于返回表达式的值。其基本语法如下:

switch (expression) {  
    case value1 -> result1;  
    case value2 -> result2;  
    // ...  
    default -> defaultResult;  
}

在这里,expression是待匹配的表达式,valueN是与之匹配的值,resultN是当expression等于valueN时返回的结果,defaultResult是当没有任何case匹配时的默认结果。

6.2.主要特性

  1. 更简洁的语法:
    • 使用箭头(->)操作符简化了case语句的书写,使得每个分支的结果更加直观。
    • 不再需要显式的break语句来结束case块,因为每个case后面的表达式在执行完毕后会自动退出switch。
  2. 更灵活的使用:
    • 支持在case表达式中使用任何合法的Java表达式,包括方法调用、算术运算等。
    • 允许在同一个case中处理多个值,使用逗号分隔即可(如case 1, 2, 3 -> ...)。
    • switch表达式可以作为值返回,这在函数式编程中非常有用。
  3. 更好的可读性:
    • 由于语法更加简洁,代码的可读性也得到了提升。
    • 可以通过合理的命名和注释来进一步提高代码的可读性。
  4. 支持复杂的模式匹配:
    • 虽然基本的switch表达式主要支持常量匹配,但Java也在不断探索在switch表达式中引入更复杂的模式匹配(如字符串、枚举、范围等)的可能性。

6.3.示例代码

以下是一个使用增强的switch表达式的示例代码:

public class SwitchExpressionExample {  
    public static void main(String[] args) {  
        int day = 3;  
        String dayOfWeek = switch (day) {  
            case 1 -> "Monday";  
            case 2 -> "Tuesday";  
            case 3 -> "Wednesday";  
            case 4 -> "Thursday";  
            case 5 -> "Friday";  
            case 6 -> "Saturday";  
            case 7 -> "Sunday";  
            default -> throw new IllegalArgumentException("Invalid day of the week: " + day);  
        };  
        System.out.println("Day of the week: " + dayOfWeek);  
    }  
}

在这个示例中,我们根据day变量的值来返回对应的星期几字符串。如果day的值不在1到7之间,则抛出异常。

7.文本块标准化

Java中的文本块(Text Blocks)标准化主要指的是从预览特性到正式特性的转变过程,以及相关的语法规则和使用规范。文本块是Java 13中引入的一个预览特性,旨在简化多行字符串和格式化字符串的编写工作。经过多个版本的迭代,文本块在Java 17中成为正式特性。

7.1.文本块的标准化历程

  1. 引入与预览:
    • Java 13:文本块作为预览特性首次引入,允许开发者以更自然的方式编写跨越多行、包含特殊字符或需要特定格式的字符串。
    • Java 14:文本块继续作为预览特性提供,进一步改进和完善。
    • Java 15:虽然文本块在Java 15中仍然是预览特性,但已经为最终成为正式特性做好了准备。
  2. 正式特性:
    • Java 17:文本块在Java 17中成为正式特性,标志着其语法和行为的标准化。

7.2.文本块的标准化内容

  1. 语法规则:
    • 文本块使用三重双引号(""")作为开始和结束的分隔符。
    • 开始分隔符必须单独成行,且后面可以跟随零个或多个空格以及一个行结束符。
    • 文本块的内容直接按原样保留格式和换行,无需使用\n来手动插入换行符。
    • 文本块会自动处理字符串中的换行和缩进,使得代码更加清晰易读。
    • 在大多数情况下,文本块中的引号、反斜杠等特殊字符无需转义。
  2. 使用场景:
    • 文本块特别适合于编写SQL查询、HTML、JSON等需要跨越多行且格式化的文本内容。
    • 文本块可以作为方法参数传递,也可以在任何可以使用字符串文本的位置使用。
  3. 格式化与缩进:
    • 文本块会删除所有附带的缩进(即与第一行非空白内容相比,前面多余的空格或制表符),只保留必要的缩进。
    • 如果需要保留尾部的空格,可以使用\s转义字符。
    • 文本块中的换行符会被统一转换为LF(\u000A),以消除不同平台间的差异。
  4. 兼容性:
    • 尽管文本块在Java 17中成为正式特性,但在团队协作或维护旧项目时,仍需考虑兼容性问题。
    • 确保项目环境和团队已准备好采用这一新特性,以避免潜在的兼容性问题。

8.模式匹配

Java中的模式匹配(Pattern Matching)是一种用于简化代码的特性,它允许开发者以更直观和简洁的方式检查对象的类型并提取其值。这一特性在Java 14及更高版本中得到了引入和逐步增强,特别是在Java 17中,switch语句对模式匹配的支持变得更加完善。以下是关于Java中模式匹配的详细解析:

8.1.模式匹配的基本概念

模式匹配是一种通用的技术,用于匹配各种类型的数据,包括字符串、树、列表等。在Java中,模式匹配主要用于以下方面:

  1. 检查对象的类型:通过模式匹配,开发者可以检查一个对象是否属于特定的类型。
  2. 从对象中提取值:如果对象匹配特定的类型,模式匹配还可以允许开发者从该对象中提取值。

8.2.模式匹配的语法和用法

8.2.1. instanceof的简化

在Java 14及更高版本中,instanceof操作符得到了简化,允许在检查对象类型的同时进行类型转换。以前,我们需要显式地将对象转换为目标类型,现在可以直接在instanceof表达式中声明一个变量来接收转换后的对象。

示例

Object obj = "Hello, World!";  
if (obj instanceof String str) {  
    System.out.println("The string length is: " + str.length());  
} else {  
    System.out.println("Not a string");  
}

8.2.2. switch表达式的增强

从Java 12开始,switch表达式引入了预览特性,支持在case语句中使用模式匹配。在Java 17中,这一特性成为标准,使得switch语句更加强大和灵活。

示例

Object obj = "Java";  
String result = switch (obj) {  
    case String s && s.length() > 4 -> "Long string";  
    case String s -> "Short string";  
    default -> "Not a string";  
};  
System.out.println(result);

8.2.3. 记录类型(Record Types)与模式匹配

记录类型在Java 14中首次引入,并在Java 16中正式成为标准。它们提供了一种简洁的方式来定义数据载体,结合模式匹配可以方便地解构和操作这些数据。

示例

record Person(String name, int age) {}  
  
Person person = new Person("Alice", 30);  
if (person instanceof Person(String name, int age)) {  
    System.out.println("Name: " + name + ", Age: " + age);  
} else {  
    System.out.println("Not a Person");  
}

8.3模式匹配的优势

  1. 简化代码:通过减少冗长的代码和重复的类型检查,模式匹配使得代码更加简洁。
  2. 提高可读性:简化的语法和直观的匹配方式提高了代码的可读性。
  3. 增强灵活性:增强的switch表达式和记录类型结合模式匹配,使得Java在处理复杂条件和数据结构时更加灵活。

9.Stream流处理

Java中的Stream流处理是Java 8引入的一个关键抽象概念,它允许你以声明方式处理数据集合(包括数组、集合等)。Stream API可以让你以一种高效且易于表达的方式来对数据进行过滤、排序、映射等复杂操作。使用Stream API可以极大地提高代码的可读性和可维护性,同时可以利用多核处理器的优势进行并行处理。

9.1.Stream的基本概念

  • 流(Stream):是一个来自数据源的元素队列并支持聚合操作。
  • 数据源:流的来源,可以是数组、集合、I/O通道等。
  • 聚合操作:在一个流上进行的操作,如过滤、映射、排序、归约等。

9.2.Stream的特点

  1. 非破坏性:流操作不会修改源数据集合。
  2. 中间操作与终端操作:流操作分为中间操作和终端操作。中间操作返回流本身,可以链式调用;终端操作返回某种结果或副作用,并结束流。
  3. 惰性求值:中间操作不会立即执行,直到遇到终端操作才开始计算整个流的操作链。
  4. 并行与串行:流操作可以是串行的,也可以是并行的。并行流利用多核处理器来加速处理过程。

9.3.Stream的基本操作

9.3.1. filter() - 过滤

过滤出满足条件的元素。

import java.util.Arrays;  
import java.util.List;  
import java.util.stream.Collectors;  
  
public class StreamExample {  
    public static void main(String[] args) {  
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);  
  
        List<Integer> evenNumbers = numbers.stream()  
                .filter(n -> n % 2 == 0)  
                .collect(Collectors.toList());  
  
        System.out.println(evenNumbers); // 输出: [2, 4, 6, 8, 10]  
    }  
}

9.3.2. map() - 映射

将流中的每个元素映射到另一个元素上。

import java.util.Arrays;  
import java.util.List;  
import java.util.stream.Collectors;  
  
public class StreamExample {  
    public static void main(String[] args) {  
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");  
  
        List<String> upperCaseNames = names.stream()  
                .map(String::toUpperCase)  
                .collect(Collectors.toList());  
  
        System.out.println(upperCaseNames); // 输出: [ALICE, BOB, CHARLIE]  
    }  
}

9.3.3. sorted() - 排序

对流中的元素进行排序。

import java.util.Arrays;  
import java.util.List;  
import java.util.stream.Collectors;  
  
public class StreamExample {  
    public static void main(String[] args) {  
        List<String> names = Arrays.asList("Bob", "Alice", "Charlie");  
  
        List<String> sortedNames = names.stream()  
                .sorted()  
                .collect(Collectors.toList());  
  
        System.out.println(sortedNames); // 输出: [Alice, Bob, Charlie]  
    }  
}

9.3.4. collect() - 收集

将流中的元素累积成一个汇总结果,如列表、集合等。

已在上面的示例中使用。

9.3.5. forEach() - 遍历

对流中的每个元素执行操作。

import java.util.Arrays;  
import java.util.List;  
  
public class StreamExample {  
    public static void main(String[] args) {  
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");  
  
        names.stream()  
                .forEach(name -> System.out.println(name));  
        // 输出:  
        // Alice  
        // Bob  
        // Charlie  
    }  
}

9.3.6. reduce() - 归约

通过反复结合流中的元素,得到一个值,如求和、求最大值等。

import java.util.Arrays;  
import java.util.List;  
  
public class StreamExample {  
    public static void main(String[] args) {  
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);  
  
        int sum = numbers.stream()  
                .reduce(0, Integer::sum);  
  
        System.out.println(sum); // 输出: 15  
    }  
}

这些示例展示了 Stream API 的一些基本用法,你可以根据自己的需求组合使用这些方法来处理数据。

9.4.示例

以下是一个简单的Stream API使用示例,演示了如何过滤集合中的元素并计算其和:

import java.util.Arrays;  
import java.util.List;  
import java.util.stream.Collectors;  
  
public class StreamExample {  
    public static void main(String[] args) {  
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);  
  
        // 过滤出偶数,映射为字符串,并收集到一个新的列表中  
        List<String> evenNumbersAsString = numbers.stream()  
                .filter(n -> n % 2 == 0)  
                .map(String::valueOf)  
                .collect(Collectors.toList());  
  
        System.out.println(evenNumbersAsString); // 输出: [2, 4, 6, 8, 10]  
  
        // 计算偶数之和  
        int sumOfEvens = numbers.stream()  
                .filter(n -> n % 2 == 0)  
                .mapToInt(Integer::intValue)  
                .sum();  
  
        System.out.println(sumOfEvens); // 输出: 30  
    }  
}

在这个示例中,我们首先通过.stream()方法将集合转换为流,然后通过.filter()方法过滤出偶数,再通过.map()方法将每个偶数映射为字符串,最后通过.collect(Collectors.toList())方法收集到一个新的列表中。我们还展示了如何使用流来计算偶数之和。

9.5.注意事项

  • 尽量避免在流操作中创建复杂的状态,因为这可能会破坏流的惰性求值和并行处理的优势。
  • 在使用并行流时,需要注意线程安全问题,因为并行流会在多个线程上执行操作。
  • 流操作的结果通常是不可变的,因此不能修改流中的元素。如果需要修改,可以在终端操作中使用集合的修改方法。

标签:Java,String,17,System,特性,JDK8,println,java,out
From: https://www.cnblogs.com/tubby233/p/18361158

相关文章

  • P10633 BZOJ2989 数列/BZOJ4170 极光 题解
    题目传送门前置知识CDQ分治|权值树状数组及应用|曼哈顿距离与切比雪夫距离的相互转化解法增加一维为时间戳,那么操作\(1\)等价于单点加。曼哈顿距离直接跑CDQ分治,貌似不太可做,考虑转化为切比雪夫距离。原曼哈顿坐标系中的点\((x_{1},y_{1}),(x_{2},y_{2})\)间的......
  • HTML5新特性之Canvas
    <canvas>是⼀个HTML元素,我们可以将它简单理解为⼀个画板,通过Canvas提供的绘制api我们就可以绘制出各种图形。一、基础1、渲染上下文●getContext('2d')●getContext('webgl')<body><canvasid="canvas"width="800"height="800"style="back......
  • 洛谷P1786
    6.帮贡排序题目链接:[P1786帮贡排序-洛谷|计算机科学教育新生态(luogu.com.cn)]()题目背景在absi2011的帮派里,死号偏多。现在absi2011和帮主等人联合决定,要清除一些死号,加进一些新号,同时还要鼓励帮贡多的人,对帮派进行一番休整。题目描述目前帮派内共最多有一位帮主,......
  • Solution - Atcoder ARC171D Rolling Hash
    对于这个\(\operatorname{hash}(A_L,\cdots,A_R)\),一个比较经典的想法是做差分,即令\(s_i=\sum\limits_{j=1}^iA_jB^{i-j}\)。于是\(\operatorname{hash}(A_L,\cdots,A_R)=s_R-s_{L-1}\timesB^{R-L+1}\not=0\)。那么也就是\(s_R\not=s_{L-1}\ti......
  • 817子鱼视频企划
    视频的拍摄题材为漫展摄影师介绍,同个cos角色,每位摄影出一张图,线下不用限时,我好了群里说一声,谁有空闲时间我就过来每位参与录制的朋友们出一张图就行,不用考虑我满不满意,拍到有一张您满意的就行视频画面可以录制第三者视角,不想出镜的话也可以用action第一视角拍我,我带了action。......
  • Visual Studio 2022 v17.11 发布
    VisualStudio2022版本17.11正式发布(GA),此版本主要是基于用户反馈的各项改进。“每项增强、每项修复和每项新功能均根据你的反馈而制定。无论你是在构建Web、桌面、云还是游戏应用程序,VisualStudio2022v17.11都旨在让你的开发体验更流畅、更快速、更直观。”提高生产......
  • springboot校园失物招领系统-计算机毕业设计源码17082
    目 录摘要1绪论1.1研究背景1.2 研究意义1.3论文结构与章节安排2 相关技术介绍2.1B/S结构2.2SpringBoot框架2.3MySQL数据库3系统分析3.1可行性分析3.2系统流程分析3.2.1数据新增流程3.2.2 数据删除流程3.3 系统功能分析3.3.1......
  • 【动画进阶】神奇的卡片 Hover 效果与 Blur 的特性探究
    本文,我们将一起探讨探讨,如下所示的一个卡片Hover动画,应该如何实现:这个效果的几个难点:鼠标移动的过程中,展示当前卡片边缘的border以及发光效果;效果只出现在鼠标附近?这一块的实现方法就有很多种了,可以计算鼠标附近的范围,在范围内去实现的效果,但是这样成本太高了。转换一......
  • C++-练习-17
    题目:结构CandyBar包含3个成员,第一个成员存储了糖块的品牌;第二个成员存储糖块的重量(可以有小数);第三个成员存储了糖块的卡路里含量(整数)。请编写一个程序,要声明这个结构,创建一个名为sncak的CandyBar变量,并将其成员分别初始化为“MochaMunch”,2.3和350。初始化应在声明snack时进......
  • IntelliJ IDEA全新版的0个新特性【送源码】
    jetBrains刚刚发布了最新IntelliJIDEA 2024.2版本,做了不少优化性能方面的优化,同时新的ui也默认为启动ui。感兴趣的小伙伴可以下载体验,以下为官方本次介绍:借助IntelliJIDEA2024.2Ultimate,您可以直接在IDE中运行SpringDataJPA方法进行即时仓库查询验证。它还通过提......