22.java8新特性

文章目录

  • `Lambda表达式`
      • Lambda表达式的基本语法
      • 示例
      • 函数接口
      • 参数与类型推断
      • 函数式接口的预定义类型
  • `自定义函数接口`
      • 例子
  • `分类`
      • 消费型接口(Consumer)
      • 供给型接口(Supplier)
      • 函数型接口(Function)
      • 断言型接口(Predicate)
      • 运算型接口(UnaryOperator)
      • 动作型接口(Runnable)
  • `消费型`
  • `供给型`
  • `函数型`
  • `断言型`
  • `方法和构造器引用`
      • 方法引用(Method Reference):
      • 构造器引用(Constructor Reference):
      • 示例:
  • `streamAPI`
    • 创建流
      • 1. 从集合创建流:
      • 2. 从数组创建流:
      • 3. 使用Stream.of创建流:
      • 4. 通过生成流的方式:
        • a. 使用 Stream.iterate:
        • b. 使用 Stream.generate:
      • 5. 从文件创建流:
      • 6. 使用特殊值创建流:
    • 中间操作
      • 1. **Filter(过滤):**
      • 2. **Map(映射):**
      • 3. **FlatMap(扁平映射):**
      • 4. **Distinct(去重):**
      • 5. **Sorted(排序):**
      • 6. **Peek(查看):**
  • 终止操作
      • 1. **forEach(遍历):**
      • 2. **count(计数):**
      • 3. **collect(收集):**
      • 4. **reduce(归约):**
      • 5. **anyMatch、allMatch、noneMatch(匹配):**
      • 6. **min、max(最小值、最大值):**
  • Optional 类
      • 创建 Optional 对象:
      • 获取值:
      • 判断是否包含值:
      • 使用 map 处理值:
      • 使用过滤器过滤值:
      • 使用 flatMap 处理嵌套的 Optional:

Lambda表达式

Lambda表达式是Java 8引入的一项重要特性,它为Java语言引入了函数式编程的概念。Lambda表达式使得代码更为简洁、可读,并且支持更灵活的编程方式。下面是Lambda表达式的一些详细信息:

Lambda表达式的基本语法

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

(parameters) -> expression

或者

(parameters) -> { statements; }
  • parameters:参数列表,类似于方法的参数列表,可以为空或非空。
  • ->:Lambda运算符,分隔参数列表和Lambda表达式的主体。
  • expression:Lambda表达式的执行体,可以是单个表达式。
  • { statements; }:Lambda表达式的执行体,可以是一个代码块,包含多个语句。

示例

下面是一个简单的Lambda表达式示例,实现了一个简单的函数接口:

// 使用匿名内部类
Runnable runnable1 = new Runnable() {@Overridepublic void run() {System.out.println("Hello from anonymous class!");}
};// 使用Lambda表达式
Runnable runnable2 = () -> System.out.println("Hello from Lambda!");// 调用
runnable1.run();
runnable2.run();

函数接口

Lambda表达式需要与函数接口(Functional Interface)一起使用。函数接口是只包含一个抽象方法的接口,可以使用@FunctionalInterface注解来确保它是函数接口。Lambda表达式可以与任何函数接口匹配。

@FunctionalInterface
interface MyFunctionalInterface {void myMethod();
}MyFunctionalInterface myLambda = () -> System.out.println("Hello from Lambda!");// 调用
myLambda.myMethod();

参数与类型推断

Lambda表达式可以自动推断参数的类型,也可以省略参数的类型声明。例如:

// 无参数的Lambda表达式
() -> System.out.println("Hello");// 单参数的Lambda表达式
x -> x * x;// 多参数的Lambda表达式
(x, y) -> x + y;

函数式接口的预定义类型

Java 8引入了一些预定义的函数式接口,如ConsumerPredicateFunction等。这些接口可以用于Lambda表达式的参数类型。

// Consumer接口,接受一个参数,无返回值
Consumer<String> printUpperCase = str -> System.out.println(str.toUpperCase());// Predicate接口,接受一个参数,返回boolean值
Predicate<Integer> isEven = num -> num % 2 == 0;// Function接口,接受一个参数,返回一个结果
Function<Integer, String> intToString = num -> String.valueOf(num);

Lambda表达式是Java 8引入的一个强大功能,它使得编写函数式风格的代码更为容易。通过使用Lambda表达式,可以实现更简洁、清晰、灵活的代码。

自定义函数接口

在Java中,可以通过自定义接口并使用@FunctionalInterface注解来创建自定义的函数接口。一个函数接口只能有一个抽象方法,但可以包含多个默认方法或静态方法。下面是一个简单的自定义函数接口的例子:

@FunctionalInterface
interface MyCustomFunctionalInterface {// 抽象方法void myMethod();// 默认方法default void defaultMethod() {System.out.println("Default method in the interface");}// 静态方法static void staticMethod() {System.out.println("Static method in the interface");}
}

在上面的例子中:

  • MyCustomFunctionalInterface是一个自定义的函数接口。
  • myMethod是该接口的抽象方法,只包含一个方法。
  • defaultMethod是一个默认方法,可以在接口中提供默认的实现。
  • staticMethod是一个静态方法,可以在接口中提供静态方法。

你可以使用这个自定义函数接口并通过Lambda表达式来实现其抽象方法:

MyCustomFunctionalInterface myLambda = () -> System.out.println("Hello from myMethod");// 调用抽象方法
myLambda.myMethod();// 调用默认方法
myLambda.defaultMethod();// 调用静态方法
MyCustomFunctionalInterface.staticMethod();

这样,你就创建了一个自定义的函数接口,并通过Lambda表达式实现了它的抽象方法。这种方式使得你能够定义自己的函数式接口,以便在项目中更灵活地使用Lambda表达式。

例子

当你需要执行某种操作时,你可以定义一个适合Lambda表达式的自定义函数接口。下面是一个简单的例子,假设你想要定义一个能够执行两个整数相加的函数接口:

@FunctionalInterface
interface MyAddition {int add(int a, int b);
}

这是一个非常简单的函数接口,只有一个抽象方法 add,接受两个整数参数并返回它们的和。现在,你可以使用这个自定义函数接口来创建Lambda表达式,并执行加法操作:

public class CustomFunctionalInterfaceExample {public static void main(String[] args) {// 使用Lambda表达式实现加法操作MyAddition addition = (a, b) -> a + b;// 调用add方法int result = addition.add(5, 3);System.out.println("Result: " + result);}
}

在这个例子中,MyAddition函数接口充当了一个加法操作的定义,Lambda表达式 (a, b) -> a + b 实现了 add 方法的具体逻辑。最后,通过调用 add 方法,你可以得到两个整数的和,并输出结果。这是一个简单的例子,但它展示了如何创建和使用自定义的函数接口。

分类

函数式接口可以分为几个主要的类别,这些类别基于接口中的抽象方法数量和签名。在Java中,函数式接口通常用于支持Lambda表达式。以下是一些常见的函数式接口分类:

  1. 消费型接口(Consumer)

    • 描述:接受一个参数,但没有返回值。
    • 示例Consumer<T>
  2. 供给型接口(Supplier)

    • 描述:不接受任何参数,但有返回值。
    • 示例Supplier<T>
  3. 函数型接口(Function)

    • 描述:接受一个参数,并返回一个结果。
    • 示例Function<T, R>
  4. 断言型接口(Predicate)

    • 描述:接受一个参数,并返回一个布尔值。
    • 示例Predicate<T>
  5. 运算型接口(Operator)

    • 描述:接受一个参数,进行一些操作,并返回结果(通常用于修改输入参数)。
    • 示例UnaryOperator<T>(一元运算符),BinaryOperator<T>(二元运算符)。
  6. 功能组合接口

    • 描述:组合了多个基本函数接口,通常用于构建更复杂的操作。
    • 示例BiFunction<T, U, R>(接受两个参数并返回结果),UnaryOperator<T>(一元运算符)等。
  7. 动作型接口(Runnable、Callable等)

    • 描述:通常不接受参数或者参数没有语义上的意义,也没有返回值。
    • 示例RunnableCallable<T>
  8. 特化的函数式接口

    • 描述:Java 8引入了一系列特化的函数式接口,如IntConsumerLongFunction<R>等,用于处理特定的数据类型,避免装箱拆箱的性能开销。

示例代码:

// Consumer接口
Consumer<String> printUpperCase = str -> System.out.println(str.toUpperCase());// Supplier接口
Supplier<Integer> randomNumber = () -> (int) (Math.random() * 100);// Function接口
Function<Integer, String> intToString = num -> String.valueOf(num);// Predicate接口
Predicate<Integer> isEven = num -> num % 2 == 0;// UnaryOperator接口
UnaryOperator<Integer> square = x -> x * x;// BinaryOperator接口
BinaryOperator<Integer> add = (a, b) -> a + b;

这些接口提供了不同类型的操作,使得在使用Lambda表达式时更加灵活和方便。选择适当的函数式接口取决于你希望执行的操作的特性。
好的,我将为你提供一些Lambda表达式的练习,涵盖不同类型的函数式接口。每个练习都有一个简单的任务,你可以使用Lambda表达式来实现。请注意,这些练习旨在帮助你熟悉Lambda表达式的不同应用场景。

消费型接口(Consumer)

  1. 创建一个Consumer<String>,用于打印字符串的大写形式。
Consumer<String> printUpperCase = // Lambda表达式实现
printUpperCase.accept("hello"); // 输出: HELLO

供给型接口(Supplier)

  1. 创建一个Supplier<Integer>,用于生成一个随机整数。
Supplier<Integer> randomNumber = // Lambda表达式实现
int number = randomNumber.get();
System.out.println("Random Number: " + number);

函数型接口(Function)

  1. 创建一个Function<Integer, String>,将整数转换为对应的星期几字符串。
Function<Integer, String> intToDay = // Lambda表达式实现
String day = intToDay.apply(1); // 输出: Monday

断言型接口(Predicate)

  1. 创建一个Predicate<String>,判断字符串是否为空。
Predicate<String> isNullOrEmpty = // Lambda表达式实现
boolean result = isNullOrEmpty.test("Hello");
System.out.println("Is Null or Empty: " + result); // 输出: false

运算型接口(UnaryOperator)

  1. 创建一个UnaryOperator<Integer>,用于计算一个整数的平方。
UnaryOperator<Integer> square = // Lambda表达式实现
int result = square.apply(5); // 输出: 25

动作型接口(Runnable)

  1. 创建一个Runnable,用于在控制台打印一条简单的消息。
Runnable printMessage = // Lambda表达式实现
printMessage.run(); // 输出: Hello, Lambda!

这些练习旨在帮助你练习不同类型的函数式接口的使用,以及如何使用Lambda表达式来简化代码。完成这些练习后,你应该对Lambda表达式在不同场景下的应用有更好的理解。

消费型

在Java 8中,消费型接口通常是指只接受参数而没有返回值的函数接口。一个常见的例子是Consumer接口。以下是一个简单的Java 8消费型接口练习示例:

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;public class ConsumerExample {public static void main(String[] args) {// 创建一个字符串列表List<String> languages = Arrays.asList("Java", "Python", "JavaScript", "C#", "Ruby");// 使用forEach方法遍历列表,并使用Consumer接口打印每个元素System.out.println("Printing elements using Consumer:");forEachWithConsumer(languages, (String language) -> {System.out.println(language);});// 使用匿名内部类实现Consumer接口System.out.println("\nPrinting elements using anonymous class:");forEachWithConsumer(languages, new Consumer<String>() {@Overridepublic void accept(String language) {System.out.println(language);}});}// 使用Consumer接口的forEach方法来遍历列表private static <T> void forEachWithConsumer(List<T> list, Consumer<T> consumer) {for (T element : list) {consumer.accept(element);}}
}

在这个示例中,我们创建了一个字符串列表(languages),然后使用forEachWithConsumer方法遍历列表,并通过Consumer接口打印每个元素。可以看到,通过Lambda表达式或匿名内部类,我们可以方便地传递不同的消费型接口实现来执行不同的操作。

供给型

在Java 8中,供给型接口通常是指无参数但有返回值的函数接口。一个常见的例子是Supplier接口。以下是一个简单的Java 8供给型接口练习示例:

import java.util.function.Supplier;public class SupplierExample {public static void main(String[] args) {// 使用Supplier接口生成随机数Supplier<Double> randomNumberSupplier = () -> Math.random();// 打印生成的随机数System.out.println("Random Number: " + randomNumberSupplier.get());// 使用Supplier接口生成当前时间戳Supplier<Long> currentTimeSupplier = System::currentTimeMillis;// 打印当前时间戳System.out.println("Current Time: " + currentTimeSupplier.get());}
}

在这个示例中,我们首先创建了一个Supplier接口的实现,通过Lambda表达式生成一个随机数。然后,我们使用get方法获取随机数的值并打印出来。

接着,我们创建另一个Supplier接口的实现,这次使用方法引用(System::currentTimeMillis)来获取当前时间戳。同样,我们通过get方法获取当前时间戳的值并打印出来。

这个示例演示了如何使用供给型接口来生成不同类型的值,可以根据实际需求自定义Supplier接口的实现。

函数型

在Java 8中,函数型接口是指只有一个抽象方法的接口,可以使用Lambda表达式来实现。java.util.function 包中提供了许多内置的函数型接口,比如FunctionPredicateUnaryOperator等。以下是一个简单的Java 8函数型接口练习示例:

import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;public class FunctionInterfaceExample {public static void main(String[] args) {// 使用Function接口将字符串转为大写Function<String, String> toUpperCaseFunction = str -> str.toUpperCase();String inputString = "hello world";// 打印转换前的字符串System.out.println("Original String: " + inputString);// 使用Function接口转换字符串为大写String upperCaseString = toUpperCaseFunction.apply(inputString);// 打印转换后的字符串System.out.println("Upper Case String: " + upperCaseString);// 使用Predicate接口判断一个数字是否为正数Predicate<Integer> isPositive = num -> num > 0;int number = 42;// 判断数字是否为正数System.out.println("Is " + number + " positive? " + isPositive.test(number));// 使用UnaryOperator接口对一个数字进行平方操作UnaryOperator<Integer> square = x -> x * x;int originalNumber = 7;// 打印平方前的数字System.out.println("Original Number: " + originalNumber);// 使用UnaryOperator接口进行平方操作int squaredNumber = square.apply(originalNumber);// 打印平方后的数字System.out.println("Squared Number: " + squaredNumber);}
}

在这个示例中,我们使用了Function接口将字符串转为大写,Predicate接口判断一个数字是否为正数,以及UnaryOperator接口对一个数字进行平方操作。通过Lambda表达式实现了这些接口的抽象方法。函数型接口的使用使得代码更为简洁和灵活。

断言型

在Java 8中,断言型接口通常是指具有布尔类型返回值的函数接口,主要用于在代码中进行条件判断。一个常见的例子是Predicate接口。以下是一个简单的Java 8断言型接口练习示例:

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;public class PredicateExample {public static void main(String[] args) {// 创建一个整数列表List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 使用Predicate接口判断数字是否为偶数,并打印结果System.out.println("Even numbers:");evaluate(numbers, (Integer number) -> number % 2 == 0);// 使用Predicate接口判断数字是否大于 5,并打印结果System.out.println("\nNumbers greater than 5:");evaluate(numbers, (Integer number) -> number > 5);}// 使用Predicate接口的test方法来进行条件判断private static <T> void evaluate(List<T> list, Predicate<T> predicate) {for (T element : list) {if (predicate.test(element)) {System.out.print(element + " ");}}}
}

在这个示例中,我们创建了一个整数列表(numbers),然后使用 evaluate 方法通过 Predicate 接口进行条件判断。首先,我们使用 Predicate 接口判断数字是否为偶数,然后判断数字是否大于 5。在 evaluate 方法中,我们通过调用 predicate.test(element) 执行断言,如果返回 true,则打印相应的元素。

这个示例演示了如何使用断言型接口来进行灵活的条件判断,可以根据实际需求自定义 Predicate 接口的实现。

方法和构造器引用

在Java 8中,方法引用和构造器引用是Lambda表达式的一种简化形式,用于更简洁地表示特定类型的函数式接口的实现。它们提供了一种更紧凑的语法,以便更清晰地表达代码的意图。

方法引用(Method Reference):

方法引用允许你通过方法的名称来引用它。它提供了一种简化Lambda表达式的方式,可以用更紧凑的语法来调用已经存在的方法。

有四种主要的方法引用形式:

  1. 静态方法引用:

    // 例如,假设有一个静态方法
    ClassName::staticMethodName;
    
  2. 实例方法引用:

    // 例如,假设有一个实例方法,通过对象实例引用
    instance::instanceMethodName;
    
  3. 类名引用一个实例方法:

    // 例如,假设有一个实例方法,通过类名引用,适用于静态上下文
    ClassName::instanceMethodName;
    
  4. 类名引用一个构造方法:

    // 例如,通过类名引用构造方法
    ClassName::new;
    

构造器引用(Constructor Reference):

构造器引用是一种特殊的方法引用,用于通过构造方法创建新对象。

构造器引用的语法如下:

ClassName::new;

这将引用 ClassName 类的构造方法,用于创建新的对象。

示例:

以下是一个使用方法引用和构造器引用的简单示例:

import java.util.Arrays;
import java.util.List;class Person {String name;Person(String name) {this.name = name;}static void printName(Person person) {System.out.println(person.name);}
}public class MethodAndConstructorReferenceExample {public static void main(String[] args) {List<String> names = Arrays.asList("Alice", "Bob", "Charlie");// 使用静态方法引用names.forEach(Person::printName);// 使用构造器引用List<Person> persons = Arrays.asList(new Person("Alice"),new Person("Bob"),new Person("Charlie"));persons.forEach(Person::printName);}
}

在上面的例子中,Person::printName 是一个静态方法引用,Person::new 是一个构造器引用。这两种引用形式都使代码更加简洁、易读。

streamAPI

创建流

Java 8引入了流(Stream)的概念,它是一种用于处理集合数据的新抽象。流允许你通过一系列的操作来处理集合,这些操作可以是中间操作或终端操作。

以下是如何创建流的一些方法:

1. 从集合创建流:

List<String> myList = Arrays.asList("Java", "Python", "JavaScript", "C#", "Ruby");// 从集合创建流
Stream<String> streamFromList = myList.stream();

2. 从数组创建流:

String[] array = {"Java", "Python", "JavaScript", "C#", "Ruby"};// 从数组创建流
Stream<String> streamFromArray = Arrays.stream(array);

3. 使用Stream.of创建流:

Stream<String> streamOfValues = Stream.of("Java", "Python", "JavaScript", "C#", "Ruby");

4. 通过生成流的方式:

a. 使用 Stream.iterate:
// 从0开始,每次加2,生成无限流
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 2);
b. 使用 Stream.generate:
// 生成5个随机数的流
Stream<Double> randomNumbers = Stream.generate(Math::random).limit(5);

5. 从文件创建流:

// 从文件创建流,每行作为流的元素
Path filePath = Paths.get("path/to/file.txt");
Stream<String> lines = Files.lines(filePath);

6. 使用特殊值创建流:

// 创建空流
Stream<String> emptyStream = Stream.empty();// 创建包含单个元素的流
Stream<String> singleElementStream = Stream.of("Java");// 创建包含重复元素的流
Stream<String> repeatedElementStream = Stream.generate(() -> "Java").limit(5);

这些是一些创建流的基本方法。创建流后,你可以使用各种中间操作和终端操作来对流进行处理。例如,filtermapflatMap 是一些中间操作,而 forEachcollectreduce 是一些终端操作。

中间操作

中间操作是在流上执行的操作,这些操作不会产生最终的结果,而是返回一个新的流,以便可以将多个中间操作链接在一起。以下是一些中间操作的示例:

1. Filter(过滤):

过滤操作通过给定的条件过滤流中的元素:

List<String> myList = Arrays.asList("Java", "Python", "JavaScript", "C#", "Ruby");// 过滤出长度大于3的元素
Stream<String> filteredStream = myList.stream().filter(s -> s.length() > 3);

2. Map(映射):

映射操作用于对流中的每个元素应用函数:

List<String> myList = Arrays.asList("Java", "Python", "JavaScript", "C#", "Ruby");// 将每个字符串转换为大写
Stream<String> upperCaseStream = myList.stream().map(String::toUpperCase);

3. FlatMap(扁平映射):

flatMap 将每个元素映射为一个流,然后将这些流连接成一个流:

List<List<Integer>> numbers = Arrays.asList(Arrays.asList(1, 2, 3),Arrays.asList(4, 5, 6),Arrays.asList(7, 8, 9)
);// 将嵌套列表平铺成一个流
Stream<Integer> flatMapStream = numbers.stream().flatMap(List::stream);

4. Distinct(去重):

去重操作用于移除流中的重复元素:

List<String> myList = Arrays.asList("Java", "Python", "JavaScript", "C#", "Ruby", "Java");// 去除重复元素
Stream<String> distinctStream = myList.stream().distinct();

5. Sorted(排序):

排序操作用于对流中的元素进行排序:

List<String> myList = Arrays.asList("Java", "Python", "JavaScript", "C#", "Ruby");// 对元素按字母顺序排序
Stream<String> sortedStream = myList.stream().sorted();

6. Peek(查看):

peek 操作用于查看流中的元素,常用于调试:

List<String> myList = Arrays.asList("Java", "Python", "JavaScript", "C#", "Ruby");// 打印每个元素并返回原始流
Stream<String> peekStream = myList.stream().peek(System.out::println);

这些中间操作允许你以流畅的方式对数据进行转换和处理,创建一个由多个操作链接而成的流水线。最终,通过终端操作,你可以获取结果或触发流的处理。

终止操作

终端操作是流操作的最终步骤,它们会触发流的处理,并产生一个最终的结果或副作用。以下是一些终端操作的示例:

1. forEach(遍历):

forEach 用于遍历流中的元素:

List<String> myList = Arrays.asList("Java", "Python", "JavaScript", "C#", "Ruby");// 遍历并打印每个元素
myList.stream().forEach(System.out::println);

2. count(计数):

count 用于计算流中的元素数量:

List<String> myList = Arrays.asList("Java", "Python", "JavaScript", "C#", "Ruby");// 计算流中的元素数量
long count = myList.stream().count();
System.out.println("Number of elements: " + count);

3. collect(收集):

collect 用于将流中的元素收集到一个集合或其他数据结构中:

List<String> myList = Arrays.asList("Java", "Python", "JavaScript", "C#", "Ruby");// 将元素收集到一个列表中
List<String> collectedList = myList.stream().collect(Collectors.toList());

4. reduce(归约):

reduce 用于将流中的元素归约为一个值:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);// 将元素相加,得到总和
Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b);
System.out.println("Sum: " + sum.orElse(0));

5. anyMatch、allMatch、noneMatch(匹配):

这些操作用于检查流中的元素是否匹配给定的条件:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);// 是否存在大于3的元素
boolean anyGreaterThanThree = numbers.stream().anyMatch(n -> n > 3);// 是否所有元素都大于3
boolean allGreaterThanThree = numbers.stream().allMatch(n -> n > 3);// 是否不存在小于0的元素
boolean noneLessThanZero = numbers.stream().noneMatch(n -> n < 0);

6. min、max(最小值、最大值):

minmax 用于获取流中的最小值和最大值:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);// 获取最小值
Optional<Integer> min = numbers.stream().min(Integer::compareTo);// 获取最大值
Optional<Integer> max = numbers.stream().max(Integer::compareTo);

这些是一些常见的终端操作,它们用于触发流的处理并生成最终的结果或副作用。在使用流时,选择适当的终端操作取决于你的具体需求。

Optional 类

Optional 类是 Java 8 引入的一个用于处理可能为 null 的值的容器类。它旨在减少在代码中出现的 null 引用,以避免空指针异常。

Optional 类的主要目标是通过显式声明一个值可能为空,从而鼓励程序员更加谨慎地处理可能为 null 的情况,以减少空指针异常的风险。

以下是 Optional 类的一些基本用法:

创建 Optional 对象:

  1. of 方法:

    Optional<String> optionalValue = Optional.of("Hello, World!");
    
  2. ofNullable 方法:

    String value = // some value, may be null
    Optional<String> optionalValue = Optional.ofNullable(value);
    
  3. empty 方法:

    Optional<String> emptyOptional = Optional.empty();
    

获取值:

  1. get 方法:

    Optional<String> optionalValue = Optional.of("Hello, World!");
    String value = optionalValue.get();
    

    注意:使用 get 方法时,如果 Optional 包含了 null 值,将抛出 NoSuchElementException

  2. orElse 方法:

    Optional<String> optionalValue = Optional.ofNullable(null);
    String result = optionalValue.orElse("Default Value");
    

    如果 optionalValuenull,则返回指定的默认值。

  3. orElseGet 方法:

    Optional<String> optionalValue = Optional.ofNullable(null);
    String result = optionalValue.orElseGet(() -> generateDefaultValue());
    

    如果 optionalValuenull,则通过 orElseGet 方法中提供的 Supplier 生成默认值。

判断是否包含值:

Optional<String> optionalValue = Optional.of("Hello, World!");// 判断是否包含值
boolean hasValue = optionalValue.isPresent();

使用 map 处理值:

Optional<String> optionalValue = Optional.of("Hello, World!");// 如果值存在,将其转换为大写
Optional<String> upperCaseValue = optionalValue.map(String::toUpperCase);

使用过滤器过滤值:

Optional<String> optionalValue = Optional.of("Hello, World!");// 过滤值,只有满足条件的值才会保留
Optional<String> filteredValue = optionalValue.filter(value -> value.contains("Hello"));

使用 flatMap 处理嵌套的 Optional:

Optional<String> optionalValue = Optional.of("Hello, World!");// 如果值存在,将其转换为大写,然后使用 flatMap 处理嵌套的 Optional
Optional<String> result = optionalValue.flatMap(value -> Optional.ofNullable(value.toUpperCase()));

Optional 类提供了一种更安全、更规范的处理可能为 null 的值的方式。在编写代码时,考虑使用 Optional 可以提高代码的可读性和可维护性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/663388.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

权限系统设计详解(二):IBAC 基于身份的访问控制

目录 IBAC 的概念 IBAC 的关键组件 IBAC 的实施过程 IBAC 的扩展 IBAC 的优势 IBAC 的局限性 小结 IBAC&#xff08;Identity-Based Access Control&#xff0c;基于身份的访问控制&#xff09;是信息安全管理中的一种传统访问控制模型&#xff0c;根据用户的身份&#…

【C语言】通讯录实现(下)

目录 1.进阶通讯录特点&#xff08;下&#xff09; 2.实现步骤 &#xff08;1&#xff09;保存增加的联系人数据到文件中 &#xff08;2&#xff09;加载保存的联系人数据 3.完整C语言通讯录代码 &#xff08;1&#xff09;contact.h (2)test.c (3)contact.c 4.结语 1.…

MongoDB从入门到实战之MongoDB简介

前言 相信很多同学对MongoDB这个非关系型数据库都应该挺熟悉的&#xff0c;在一些高性能、动态扩缩容、高可用、海量数据存储、数据价值较低、高扩展的业务场景下MongoDB可能是我们的首选&#xff0c;因为MongoDB通常能让我们以更低的成本解决问题&#xff08;包括学习、开发、…

嵌入式中Qt5.7.1添加支持openssl方法

1、openssl编译 版本&#xff1a;openssl-1.0.2g 一定要选对Qt版本对应的openssl版本&#xff0c;由于开始选的openssl版本不对&#xff0c;导致编译Qt时出现很多错误。 交叉编译 ./config no-asm shared --prefix/opt/Xilinx2018_zynq/zynq_openssl_1.0.2/ --cross-compile…

vivo发布2023 年度科技创新;阿里全新AI代理,可模拟人类操作手机

vivo 发布 2023 年度十大产品技术创新 近日&#xff0c;vivo 发布了「2023 年度科技创新」十大产品技术创新榜单&#xff0c;并将这些技术分为了 4 个板块。 「四大蓝科技」为 vivo 在去年推出的全新技术品牌&#xff0c;涵盖蓝晶芯片技术栈、蓝海续航系统、蓝心大模型、蓝河操…

2023年算法SAO-CNN-BiLSTM-ATTENTION回归预测(matlab)

2023年算法SAO-CNN-BiLSTM-ATTENTION回归预测&#xff08;matlab&#xff09; SAO-CNN-BiLSTM-Attention雪消融优化器优化卷积-长短期记忆神经网络结合注意力机制的数据回归预测 Matlab语言。 雪消融优化器( SAO) 是受自然界中雪的升华和融化行为的启发&#xff0c;开发了一种…

LeetCode 834. 树中距离之和

简单换根DP 其实就是看好变化量&#xff0c;然后让父亲更新儿子就好了&#xff5e; 上图2当根节点的时候&#xff0c;ans[2] ans[0] -sz[2]n-sz[2]; class Solution { public:vector<int> sumOfDistancesInTree(int n, vector<vector<int>>& edges) {v…

Java学习day26:和线程相关的Object类的方法、等待线程和唤醒线程(知识点详解)

声明&#xff1a;该专栏本人重新过一遍java知识点时候的笔记汇总&#xff0c;主要是每天的知识点题解&#xff0c;算是让自己巩固复习&#xff0c;也希望能给初学的朋友们一点帮助&#xff0c;大佬们不喜勿喷(抱拳了老铁&#xff01;) 往期回顾 Java学习day25&#xff1a;守护线…

MySQL数据导入:MySQL 导入 Excel 文件.md

简述 有时候需要往 MySQL 中导入一些 Excel 数据&#xff0c;下面来看看怎么操作吧&#xff01; 桌面处理 打开 excel 表格–>另存为–>选择格式 (CSV 逗号分割)—>保存文件 文件名 &#xff1a;test.csv 转换字符集 mac 使用文本编辑打开&#xff1a; 右键点击…

假期刷题打卡--Day20

1、MT1173魔数 一个数字&#xff0c;把他乘以二&#xff0c;会得到一个新的数字&#xff0c;如果这个新数字依然由原数中那些数字组成&#xff0c;就称原数为一个魔数。输入正整数N&#xff0c;检查它是否是一个魔数&#xff0c;输出YES或者NO。 格式 输入格式&#xff1a; …

MySQL之SQL的查询语句如何执行

文章目录 前言一、一条查询的SQL是如何执行的二、MySQL的“零件”们1.连接器2.查询缓存3.分析器4.优化器5.执行器 总结 前言 做了多年技术之后&#xff0c;技术更新换代太快&#xff0c;从我入行时候从单体架构到后面分布式SOA&#xff0c;再到微服务&#xff0c;从后端再到全…

Docker搭建MySQL8主从复制

之前文章我们了解了面试官&#xff1a;说一说Binlog是怎么实现的&#xff0c;这里我们用Docker搭建主从复制环境。 docker安装主从MySQL 这里我们使用MySQL8.0.32版本&#xff1a; 主库配置 master.cnf //基础配置 [client] port3306 socket/var/run/mysqld/mysql.sock [m…

Java项目:基于SSM框架实现的教务管理系统(ssm+B/S架构+源码+数据库+毕业论文)

一、项目简介 本项目是一套ssm813基于SSM框架实现的教务管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#x…

Docker进阶篇-DockerFile

一、简介 Dockerfile是用来构建Docker镜像的文本文件&#xff0c;是由一条条构建镜像所需的指令和参数构成的脚 本。 构建步骤&#xff1a; 1、编写Dockerfile文件 2、docker build命令构建镜像 3、docker run依镜像运行容器实例 二、Docker构建过程解析 1、Dockerfile…

2024美国大学生数学建模C题网球运动中的势头详解思路+具体代码

2024美国大学生数学建模C题网球运动中的势头详解思路具体代码 E题数据已更新&#xff0c;做E题的小伙伴推荐看看博主的E题解析文章。那么废话不多说我们继续来做C题。 赛题分析 我们先阅题&#xff1a; 在2023年温布尔登男单决赛中&#xff0c;20岁的西班牙新星卡洛斯阿尔卡…

/home/zzcg/BJCAROOT/ 把/换成File.separator

在Java中&#xff0c;File.separator 是系统相关的默认名称分隔符。对于UNIX系统&#xff0c;它是 /&#xff0c;对于Windows&#xff0c;它是 \。 所以&#xff0c;如果你想将字符串 "/home/zzcg/BJCAROOT/" 中的 / 替换为 File.separator&#xff0c;你可以这样做…

数据结构—动态查找

动态查找介绍 1. 动态查找的引入&#xff1a;当查找表以线性表的形式组织时&#xff0c;若对查找表进行插入、删除或排序操作&#xff0c;就必须移动大量的记录&#xff0c;当记录数很多时&#xff0c;这种移动的代价很大。 2. 动态查找表的设计思想&#xff1a;表结构本身是…

Midjourney新功能介绍:风格参考(Style References)详解

引言 对于追求创意和一致性的艺术家和设计师们来说&#xff0c;Midjourney的最新功能——风格参考&#xff08;Style References&#xff09;&#xff0c;无疑是一个激动人心的消息。这项测试算法的发布&#xff0c;让我们得以通过简单的URL引用&#xff0c;将特定的风格应用于…

专项审计或鉴证报告

经具有资质并符合《工作指引》相关条件的中介机构出具的企业近三个会计年度&#xff08;实际年限不足三年的按实际经营年限&#xff09;研究开发费用专项审计或鉴证报告&#xff08;附研究开发活动说明材料&#xff09;、近一个会计年度高新技术产品&#xff08;服务&#xff0…

【论文速览_01】Awesome Few Shot Segmentation论文

Awesome Few Shot Segmentation Awesome Few Shot Segmentation论文CVPR 2023Hierarchical Dense Correlation Distillation for Few-Shot Segmentation文章内容 MIANet: Aggregating Unbiased Instance and General Information for Few-Shot Semantic Segmentation文章内容 I…