提交 46bcf382 编写于 作者: W wizardforcel

2020-05-21 22:38:36

上级 f9bd6682
# Java 8 方法参考示例
# Java 8 方法引用示例
> 原文: [https://howtodoinjava.com/java8/lambda-method-references-example/](https://howtodoinjava.com/java8/lambda-method-references-example/)
[Java 8](//howtodoinjava.com/java-8-tutorial/) 中,我们可以使用`**class::methodName**`类型的语法从类或对象中引用方法。 让我们学习一下 Java 8 中可用的**方法参考的不同类型。**
[Java 8](//howtodoinjava.com/java-8-tutorial/) 中,我们可以使用`class::methodName`类型的语法从类或对象中引用方法。 让我们学习一下 Java 8 中可用的**方法引用的不同类型。**
```java
Table of Contents
......@@ -18,13 +18,14 @@ Table of Contents
Java 8 允许四种类型的方法引用。
| 方法参考 | 描述 | 方法参考示例 |
| 引用**静态方法** | 用于从类中引用静态方法 | `Math::max`等同于`Math.max(x,y)` |
| 从实例引用**实例方法** | 使用对所提供对象的引用来引用实例方法 | `System.out::println`等同于`System.out.println(x)` |
| 从类类型引用**实例方法** | 在对上下文提供的对象的引用上调用实例方法 | `String::length`等同于`str.length()` |
| 引用**构造器** | 引用构造器 | `ArrayList::new`等同于`new ArrayList()` |
| 方法引用 | 描述 | 方法引用示例 |
| --- | --- | --- |
| **静态方法**的引用 | 用于从类中引用静态方法 | `Math::max`等同于`(x, y) -> Math.max(x,y)` |
| 来自实例的**实例方法**的引用 | 使用所提供对象的引用来引用实例方法 | `System.out::println`等同于`x -> System.out.println(x)` |
| 来自类类型的**实例方法**的引用 | 在上下文提供的对象的引用上调用实例方法 | `String::length`等同于`str -> str.length()` |
| **构造器**的引用 | 引用构造器 | `ArrayList::new`等同于`() -> new ArrayList()` |
## 2\. 引用静态方法的方法 – Class :: staticMethodName
## 2\. 静态方法的引用 – `Class::staticMethodName`
使用`Math.max()`是静态方法的示例。
......@@ -43,7 +44,7 @@ max.ifPresent(value -> System.out.println(value));
433
```
## 3\. 从实例 – ClassInstance :: instanceMethodName 到实例方法的方法引用
## 3\. 来自实例的实例方法的引用 – `ClassInstance::instanceMethodName`
在上面的示例中,我们使用`System.out.println(value)`打印找到的最大值。 我们可以使用`System.out::println`打印该值。
......@@ -62,9 +63,9 @@ Output:
433
```
## 4\. 从类类型中引用实例方法的方法 – Class :: instanceMethodName
## 4\. 来自类类型的实例方法的引用 – `Class::instanceMethodName`
在此示例中,s1.compareTo(s2)称为`String::compareTo`
在此示例中,`s1.compareTo(s2)`称为`String::compareTo`
```java
List<String> strings = Arrays
......@@ -86,14 +87,14 @@ System.out.println(sortedAlt);
```
Output:
输出:
```java
[com, do, dot, how, in, java, to]
[com, do, dot, how, in, java, to]
```
## 5\. 引用构造器 – Class :: new
## 5\. 构造器的引用 – `Class::new`
可以更新第一种方法,以创建一个从 1 到 100 的整数列表。使用 [lambda 表达式](//howtodoinjava.com/java8/complete-lambda-expressions-tutorial-in-java/)非常简单。 要创建`ArrayList`的新实例,我们已经使用`ArrayList::new`
......@@ -109,7 +110,7 @@ max.ifPresent(System.out::println);
```
Output:
输出:
```java
99
......
......@@ -15,7 +15,7 @@ How conflicts are resolved while calling default methods?
## Java 8 中的默认方法是什么?
Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces.
默认方法使您可以向库的接口添加新功能,并确保与为这些接口的较早版本编写的代码二进制兼容。
顾名思义,java 8 中的默认方法就是默认的。 如果不重写它们,则它们是调用者类将调用的方法。 它们在接口中定义。
......@@ -30,7 +30,7 @@ public interface Moveable {
```
可移动接口定义方法 move(); 并提供了默认实现。 如果有任何类实现此接口,则无需实现其自己的 move()方法版本。 它可以直接调用 instance.move();
可移动接口定义方法`move()`; 并提供了默认实现。 如果有任何类实现此接口,则无需实现其自己的`move()`方法版本。 它可以直接调用`instance.move()`;
```java
public class Animal implements Moveable{
......@@ -70,9 +70,9 @@ Output: I am running
## 为什么 Java 8 需要默认方法?
这是您下一个 [**面试问题**](//howtodoinjava.com/java-interview-questions/ "Java Interview Questions") 的不错的选择。 **最简单的答案是在 Java 中启用 lambda 表达式的功能。** Lambda 表达本质上是函数式接口的类型。 为了无缝支持 lambda 表达式,必须修改所有核心类。 但是,这些核心类(例如 java.util.List)不仅在 JDK 类中实现,而且在数千个客户端代码中也实现。 核心类中任何不兼容的更改都将肯定会产生反作用,并且根本不会被接受。
这是您下一个[**面试问题**](//howtodoinjava.com/java-interview-questions/ "Java Interview Questions")的不错的选择。 **最简单的答案是在 Java 中启用 lambda 表达式的功能。** Lambda 表达本质上是函数式接口的类型。 为了无缝支持 lambda 表达式,必须修改所有核心类。 但是,这些核心类(例如`java.util.List`)不仅在 JDK 类中实现,而且在数千个客户端代码中也实现。 核心类中任何不兼容的更改都将肯定会产生反作用,并且根本不会被接受。
默认方法打破了这种僵局,并允许在核心类中添加对函数式接口的支持。 让我们来看一个例子。 以下是已添加到 java.lang.Iterable 的方法。
默认方法打破了这种僵局,并允许在核心类中添加对函数式接口的支持。 让我们来看一个例子。 以下是已添加到`java.lang.Iterable`的方法。
```java
default void forEach(Consumer<? super T> action) {
......@@ -84,7 +84,7 @@ default void forEach(Consumer<? super T> action) {
```
在 Java 8 之前,如果必须迭代 Java 集合,则将获得一个迭代器实例,并调用它的下一个方法,直到 hasNext()返回 false。 这是常见的代码,我们在日常编程中已经使用了数千次。 语法也总是相同的。 因此,我们可以使其精简吗,使其仅占用一行代码,仍然像以前一样为我们完成工作。 上面的功能可以做到这一点。
在 Java 8 之前,如果必须迭代 Java 集合,则将获得一个迭代器实例,并调用它的下一个方法,直到`hasNext()`返回`false`。 这是常见的代码,我们在日常编程中已经使用了数千次。 语法也总是相同的。 因此,我们可以使其精简吗,使其仅占用一行代码,仍然像以前一样为我们完成工作。 上面的功能可以做到这一点。
现在要迭代并对列表中的每个项目执行一些简单的操作,您需要做的是:
......@@ -106,7 +106,7 @@ public class Animal implements Moveable{
```
因此,这里,在不破坏列表的任何自定义实现的情况下,已将其他方法添加到 List 中。 长期以来,它一直是 Java 中非常需要的功能。 现在就在我们身边。
因此,这里,在不破坏列表的任何自定义实现的情况下,已将其他方法添加到`List`中。 长期以来,它一直是 Java 中非常需要的功能。 现在就在我们身边。
## 调用默认方法时如何解决冲突?
......@@ -114,9 +114,9 @@ public class Animal implements Moveable{
**解决此冲突的规则如下:**
**1)**最优选的是类中的重写方法。 如果在匹配任何内容之前找到它们,它们将被匹配并被调用。
**2)**选择在“最特定的默认提供接口”中具有相同签名的方法。 这意味着如果 Animal 类实现了两个接口,即 Moveable 和 Walkable,从而 Walkable 扩展了 Moveable。 那么 Walkable 是最具体的接口,如果方法签名匹配,则将从此处选择默认方法。
**3)**如果 Moveable 和 Walkable 是独立的接口,则会发生严重的冲突情况,并且编译器将抱怨并无法确定。 您必须通过提供额外的信息来帮助编译器,该信息应从哪个接口调用默认方法。 例如
1)最优选的是类中的重写方法。 如果在匹配任何内容之前找到它们,它们将被匹配并被调用。
2)选择在“最特定的默认提供接口”中具有相同签名的方法。 这意味着如果`Animal`类实现了两个接口,即`Moveable``Walkable`,从而`Walkable`扩展了`Moveable`。 那么`Walkable`是最具体的接口,如果方法签名匹配,则将从此处选择默认方法。
3)如果`Moveable``Walkable`是独立的接口,则会发生严重的冲突情况,并且编译器将抱怨并无法确定。 您必须通过提供额外的信息来帮助编译器,该信息应从哪个接口调用默认方法。 例如:
```java
Walkable.super.move();
......
# Java 8 Optionals:完整参考
# Java 8 `Optional`:完整参考
> 原文: [https://howtodoinjava.com/java8/java-8-optionals-complete-reference/](https://howtodoinjava.com/java8/java-8-optionals-complete-reference/)
> 原文: [https://howtodoinjava.com/java8/java-8-Optional-complete-reference/](https://howtodoinjava.com/java8/java-8-Optional-complete-reference/)
我们所有人都必须在我们的应用程序中遇到`NullPointerException`。 当您尝试利用尚未初始化的对象引用,使用 null 初始化或根本不指向任何实例的对象引用时,会发生此异常。 ***NULL 仅表示“不存在值”*** 。 罗马人很可能只是一个人,没有遇到这个空缺的问题,而是从 I,II,III 开始计数(不为零)。 也许,他们无法模拟市场上苹果的缺乏。 [:-)]
我们所有人都必须在我们的应用程序中遇到`NullPointerException`。 当您尝试利用尚未初始化的对象引用,使用`null`初始化或根本不指向任何实例的对象引用时,会发生此异常。***`NULL`仅表示“不存在值”***。 罗马人很可能只是一个人,没有遇到这个空缺的问题,而是从 I,II,III 开始计数(不为零)。 也许,他们无法模拟市场上苹果的缺乏。:-)
“我称之为我十亿美元的错误。” – [**C. A. R. Hoare 爵士**](https://en.wikipedia.org/wiki/C._A._R._Hoare "C._A._R._Hoare") ,他发明了空引用
“我称之为我十亿美元的错误。” – [**C. A. R. Hoare Hoare**](https://en.wikipedia.org/wiki/C._A._R._Hoare "C._A._R._Hoare"),他发明了空引用
在本文中,我将针对该特定用例(即 [`Optional`](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html "Optional") )讨论 [**java 8 功能之一**](//howtodoinjava.com/category/java8/ "java 8") 。 为了清楚和区分多个概念,本文分为多个部分。
在本文中,我将针对该特定用例(即[`Optional`](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html "Optional"))讨论 [**java 8 功能之一**](//howtodoinjava.com/category/java8/ "java 8")。 为了清楚和区分多个概念,本文分为多个部分。
```java
Discussion Points
1) What is the Type of Null?
2) What is wrong with just returning null?
3) How Java 8 Optionals provide the solution?
3) How Java 8 Optional provide the solution?
a) Creating Optional objects
b) Do something if a value is present
c) Default/Absent values and actions
......@@ -28,29 +28,29 @@ Discussion Points
## 1)什么是空值?
在 Java 中,我们使用引用类型来访问对象,而当我们没有特定的对象作为引用点时,则将此类引用设置为 null 表示没有值。 对?
在 Java 中,我们使用引用类型来访问对象,而当我们没有特定的对象作为引用点时,则将此类引用设置为`null`表示没有值。 对?
null 的使用是如此普遍,以至于我们很少对此多加思考。 例如,对象的字段成员会自动初始化为 null,而程序员通常会在没有初始值的引用类型时将引用类型初始化为 null,并且通常在每次我们不知道或不知道的时候都使用 null 没有参考价值。
`null`的使用是如此普遍,以至于我们很少对此多加思考。 例如,对象的字段成员会自动初始化为`null`,而程序员通常会在没有初始值的引用类型时将引用类型初始化为`null`,并且通常在每次我们不知道或不知道的时候都使用`null`没有参考价值。
FYI, in Java ***null is actually a type***, a special one. It has no name so we cannot declare variables of its type or cast any variables to it; in fact there is only a single value that can be associated with it (i.e. the literal null). Remember that unlike any other types in Java, a null reference can be safely assigned to any other reference types without any error(See [**JLS 3.10.7**](https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.7 "jls 3.10.7") and [**4.1**](https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.1 "jls 4.1")).
仅供参考,在 Java 中`null`实际上是一种类型,是一种特殊的类型。 它没有名称,因此我们不能声明其类型的变量或将任何变量强制转换为它。 实际上,只有一个可以与之关联的值(即字面值为`null`)。 请记住,与 Java 中的任何其他类型不同,可以将空引用安全地分配给任何其他引用类型,而不会出现任何错误(见 [**JLS 3.10.7**](https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.7 "jls 3.10.7")[**4.1**](https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.1 "jls 4.1"))。
## 2)仅返回 null 有什么问题?
## 2)仅返回`null`有什么问题?
通常,API 设计人员将描述性的 Java 文档放入 API 中,并在其中提到 API 可以返回空值,在这种情况下,返回值可以是 null。 现在,问题在于 API 的调用者可能由于任何原因而错过了读取 Javadoc 的操作,并且**忘记了处理空值**的情况。 肯定的将来这将是一个错误。
通常,API 设计人员将描述性的 Java 文档放入 API 中,并在其中提到 API 可以返回空值,在这种情况下,返回值可以是`null`。 现在,问题在于 API 的调用者可能由于任何原因而错过了读取 Javadoc 的操作,并且**忘记了处理空值**的情况。 肯定的将来这将是一个错误。
并且相信我,这经常发生,并且是空指针异常的主要原因之一,尽管不是唯一的原因。 因此,在这里上一课,当您第一次使用它时,请务必阅读它的 Java dcos(…至少是[[-]])
并且相信我,这经常发生,并且是空指针异常的主要原因之一,尽管不是唯一的原因。 因此,在这里上一课,当您第一次使用它时,请务必(至少)阅读它的 Javadocs
> 现在我们知道在大多数情况下 null 是一个问题,什么是最好的处理方式?
> 现在我们知道在大多数情况下`null`是一个问题,什么是最好的处理方式?
一个好的解决方案是始终**始终使用某个值**初始化您的对象引用,而永远不要使用 null 进行初始化。 这样,您将永远不会遇到`NullPointerException`。 很公平。 但实际上,我们始终没有默认值作为参考。 那么,这些案件应该如何处理?
一个好的解决方案是始终**始终使用某个值**初始化您的对象引用,而永远不要使用`null`进行初始化。 这样,您将永远不会遇到`NullPointerException`。 很公平。 但实际上,我们始终没有默认值作为参考。 那么,这些案件应该如何处理?
上述问题在许多方面都是正确的。 好吧, **java 8 `Optionals`** 是这里的答案。
上述问题在许多方面都是正确的。 好吧, **java 8 `Optional`** 是这里的答案。
## 3)Java 8 Optionals 如何提供解决方案?
## 3)Java 8 `Optional`如何提供解决方案?
可选的是用非空值替换可空 T 引用的方法。 Optional 可以包含非空 T 引用(在这种情况下,我们称该引用为“存在”),也可以不包含任何内容(在这种情况下,我们称该引用为“不存在”)。
可选的是用非空值替换可空`T`引用的方法。 `Optional`可以包含非空`T`引用(在这种情况下,我们称该引用为“存在”),也可以不包含任何内容(在这种情况下,我们称该引用为“不存在”)。
> 请记住,**从未说过可选的“包含 null”**
> 请记住,**从未说过`Optional`“包含`null`”**
```java
Optional<Integer> canBeEmpty1 = Optional.of(5);
......@@ -62,30 +62,30 @@ canBeEmpty2.isPresent(); // returns false
```
您也可以**查看“可选”为包含值或不包含**的单值容器。
您也可以**将`Optional`看做为包含或不包含值**的单值容器。
重要的是要注意,Optional 类的目的不是替换每个单个空引用。 相反,它的目的是**帮助设计更易于理解的 API** ,以便仅通过读取方法的签名即可知道是否可以期望一个可选值。 这迫使您从 Optional 中获取值并对其进行处理,同时处理 Optional 为空的情况。 好吧,这正是空引用/返回值的解决方案,最终导致`NullPointerException`
重要的是要注意,`Optional`类的目的不是替换每个单个空引用。 相反,它的目的是**帮助设计更易于理解的 API** ,以便仅通过读取方法的签名即可知道是否可以期望一个可选值。 这迫使您从`Optional`中获取值并对其进行处理,同时处理`Optional`为空的情况。 好吧,这正是空引用/返回值的解决方案,最终导致`NullPointerException`
以下是一些示例,以了解有关应如何在应用程序代码中创建和使用 Optional 的更多信息。
以下是一些示例,以了解有关应如何在应用程序代码中创建和使用`Optional`的更多信息。
## a)创建可选对象
## a)创建`Optional`对象
创建 Optional 的主要方法有 3 种。
创建`Optional`的主要方法有 3 种。
**i)**使用 **Optional.empty()**创建空的可选
i)使用`Optional.empty()`创建空的`Optional`
```java
Optional<Integer> possible = Optional.empty();
```
**ii)**使用 **Optional.of()**创建具有默认非空值的可选项。 如果在 of()中传递 null,则立即引发 NullPointerException
ii)使用`Optional.of()`创建具有默认非空值的`Optional`。 如果在`of()`中传递`null`,则立即引发`NullPointerException`
```java
Optional<Integer> possible = Optional.of(5);
```
**iii)**使用 **Optional.ofNullable()**创建一个可能包含空值的 Optional 对象。 如果 parameter 为 null,则生成的 Optional 对象将为空(请记住,该值不存在;请勿将其读取为 null)。
iii)使用`Optional.ofNullable()`创建一个可能包含空值的`Optional`对象。 如果参数为`null`,则生成的`Optional`对象将为空(请记住,该值不存在;请勿将其读取为`null`)。
```java
Optional<Integer> possible = Optional.ofNullable(null);
......@@ -93,7 +93,7 @@ Optional<Integer> possible = Optional.ofNullable(null);
Optional<Integer> possible = Optional.ofNullable(5);
```
## b)如果存在可选值,则执行某些操作
## b)如果存在`Optional`值,则执行某些操作
第一步是获取`Optional`对象。 现在,在检查其内部是否包含任何值之后,再使用它。
......@@ -116,7 +116,7 @@ if(possible.isPresent()){
## c)默认/不存在的值和动作
如果确定操作结果为空,则编程中的典型模式是返回默认值。 通常,您可以使用三元运算符。 但是使用 Optionals,您可以编写如下代码:
如果确定操作结果为空,则编程中的典型模式是返回默认值。 通常,您可以使用三元运算符。 但是使用`Optional`,您可以编写如下代码:
```java
//Assume this value has returned from a method
......@@ -142,15 +142,15 @@ companyOptional.filter(department -> "Finance".equals(department.getName())
```
[**过滤方法**](//howtodoinjava.com/java8/java-8-tutorial-streams-by-examples/ "java 8 streams")[**谓词**](//howtodoinjava.com/2014/04/04/how-to-use-predicate-in-java-8/ "predicate") 为参数。 如果`Optional`对象中存在一个值,并且该值与谓词匹配,则 filter 方法将返回该值;否则,该方法将返回该值。 否则,它返回一个空的`Optional`对象。 如果在[`Stream`](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html "Stream")接口中使用了 filter 方法,则可能已经看到了类似的模式。
[**过滤方法**](//howtodoinjava.com/java8/java-8-tutorial-streams-by-examples/ "java 8 streams")[**谓词**](//howtodoinjava.com/2014/04/04/how-to-use-predicate-in-java-8/ "predicate")为参数。 如果`Optional`对象中存在一个值,并且该值与谓词匹配,则过滤方法将返回该值;否则,该方法将返回该值。 否则,它返回一个空的`Optional`对象。 如果在[`Stream`](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html "Stream")接口中使用了过滤方法,则可能已经看到了类似的模式。
很好,这段代码看起来更接近问题语句,并且没有妨碍我们进行冗长的 null 检查!
很好,这段代码看起来更接近问题语句,并且没有妨碍我们进行冗长的`null`检查!
哇!! 从编写痛苦的嵌套 null 检查到编写可编写,可读且可更好地免受 null 指针异常保护的声明性代码,我们已经走了很长一段路。
哇!! 从编写痛苦的嵌套`null`检查到编写可编写,可读且可更好地免受`null`指针异常保护的声明性代码,我们已经走了很长一段路。
## 4)Optional 内部有什么使它起作用?
## 4)`Optional`内部有什么使它起作用?
如果打开 Optional.java 的源代码,则会发现 Optional 持有的值定义为:
如果打开`Optional.java`的源代码,则会发现`Optional`持有的值定义为:
```java
/**
......@@ -160,7 +160,7 @@ private final T value;
```
并且,如果您定义一个空的 Optional,则它声明如下。 **静态关键字可确保每个 VM** 通常仅存在一个空实例。
并且,如果您定义一个空的`Optional`,则它声明如下。 **静态关键字可确保每个 VM** 通常仅存在一个空实例。
```java
/**
......@@ -170,16 +170,16 @@ private static final Optional<?> EMPTY = new Optional<>();
```
默认的 **no-args 构造器是 define private** ,因此您无法创建 Optional 的实例,但上述三种方法除外。
默认的**无参构造器定义为私有** ,因此您无法创建`Optional`的实例,但上述三种方法除外。
当您创建一个 Optional 时,最终会发生以下调用,并将传递的值分配给“ value”属性。
当您创建一个`Optional`时,最终会发生以下调用,并将传递的值分配给“`value`”属性。
```java
this.value = Objects.requireNonNull(value);
```
当您尝试从可选获取**的值时,如果抛出了其他情况`NoSuchElementException`,则会获取该值:**
当您尝试从`Optional`获取值时,如果没有抛出`NoSuchElementException`,则会获取该值:
```java
public T get() {
......@@ -191,19 +191,19 @@ public T get() {
```
同样,在 Optional 类中定义的其他函数仅在“值”属性附近起作用。 浏览 Optional.java 的 [**源代码以获取更多信息。**](http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/Optional.java "Optional.java")
同样,在`Optional`类中定义的其他函数仅在“`value`”属性附近起作用。 浏览`Optional.java`[**源代码**](http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/Optional.java "Optional.java")以获取更多信息。
## 5)可选试图解决什么?
## 5)`Optional`试图解决什么?
`Optional`尝试通过考虑到有时缺少返回值来增加构建更具表现力的 API 的可能性,从而减少 Java 系统中空指针异常的数量。 如果从一开始就存在`Optional`,那么今天大多数库和应用程序可能会更好地处理缺少的返回值,从而减少了空指针异常的数量以及总体上的错误总数。
通过使用`Optional`,用户不得不考虑特殊情况。 除了因提供空名而提高了可读性之外,Optional 的**最大优点是其防白痴**。 如果您要完全编译程序,它会迫使您积极考虑不存在的情况,因为您必须主动展开 Optional 并解决该失败情况。
通过使用`Optional`,用户不得不考虑特殊情况。 除了因提供空名而提高了可读性之外,`Optional`**最大优点是其防白痴**。 如果您要完全编译程序,它会迫使您积极考虑不存在的情况,因为您必须主动展开`Optional`并解决该失败情况。
## 6)Optional 不尝试解决的问题是什么?
## 6)`Optional`不尝试解决的问题是什么?
可选的是**并不是要避免所有类型的空指针**的机制。 例如方法和构造器的强制输入参数仍然必须进行测试。
`Optional`**并不是要避免所有类型的空指针**的机制。 例如方法和构造器的强制输入参数仍然必须进行测试。
就像使用 null 时一样,**可选**不能帮助传达缺失值的含义。 因此,该方法的调用者仍然必须检查 API 的 javadoc,以了解缺少**可选**的含义,以便对其进行正确处理。
就像使用`null`时一样,`Optional`不能帮助传达缺失值的含义。 因此,该方法的调用者仍然必须检查 API 的 javadoc,以了解缺少`Optional`的含义,以便对其进行正确处理。
请注意,`Optional`不能在以下情况下使用,因为它可能不会给我们带来任何好处:
......@@ -212,20 +212,21 @@ public T get() {
* 在方法的输入参数中
* 在构造器参数中
## 7)应该如何使用可选的
## 7)应该如何使用`Optional`
**几乎在所有时间 ***都应该使用可选的**作为可能不返回值的函数*** 的返回类型。
**几乎在所有时间**都应该使用`Optional`**作为可能不返回值的函数**的返回类型。
这是来自 OpenJDK 邮件列表的报价
这是来自 OpenJDK 邮件列表的引言
> JSR-335 EG 相当强烈地认为 Optional 不应仅用于支持 option-return 成语。
> 有人建议甚至将其重命名为“ ***OptionalReturn*** ”。
> JSR-335 EG 相当强烈地认为`Optional`不应仅用于支持 option-return 惯例。
>
> 有人建议甚至将其重命名为“`OptionalReturn`”。
从本质上讲,这意味着`Optional`仅应在确实达到目的的情况下用作某些服务,存储库或实用程序方法的返回类型。
## 8)结论
在本文中,我们了解了如何采用新的 **Java SE 8 `java.util.Optional`****可选**的目的不是替换代码库中的每个单个 null 引用,而是帮助您设计更好的 API,其中,仅通过读取方法的签名,用户就可以知道是否期待并妥善处理`Optional`值。
在本文中,我们了解了如何采用新的 **Java SE 8 `java.util.Optional`**`Optional`的目的不是替换代码库中的每个单个`null`引用,而是帮助您设计更好的 API,其中,仅通过读取方法的签名,用户就可以知道是否期待并妥善处理`Optional`值。
仅此功能就可以了。 在评论部分让我知道您的想法。
......
......@@ -2,23 +2,23 @@
> 原文: [https://howtodoinjava.com/java8/how-to-use-predicate-in-java-8/](https://howtodoinjava.com/java8/how-to-use-predicate-in-java-8/)
在数学中,**谓词**通常被理解为**布尔值函数** `'P: X? {true, false}'`,称为 X 谓词。 可以将其视为返回`true``false`值的运算符或函数。
在数学中,**谓词**通常被理解为**布尔值函数**`'P: X? {true, false}'`,称为`X`谓词。 可以将其视为返回`true``false`值的运算符或函数。
## Java 8 谓词用法
在 Java 8 中,[谓词](https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html)[函数式接口](https://howtodoinjava.com/java8/functional-interface-tutorial/),因此可以用作 [**lambda 表达式**](//howtodoinjava.com/java8/complete-lambda-expressions-tutorial-in-java/ "Complete lambda expressions tutorial") 或方法参考的分配目标。 那么,您认为如何,我们可以在日常编程中使用这些 true / false 返回函数? 我会说,您可以在需要求值类似对象的组/集合上的条件的任何地方使用谓词,以便求值可以得出 true 或 false
在 Java 8 中,[谓词](https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html)[函数式接口](https://howtodoinjava.com/java8/functional-interface-tutorial/),因此可以用作 [**lambda 表达式**](//howtodoinjava.com/java8/complete-lambda-expressions-tutorial-in-java/ "Complete lambda expressions tutorial") 或方法参考的分配目标。 那么,您认为如何,我们可以在日常编程中使用这些`true`/`false`返回函数? 我会说,您可以在需要求值类似对象的组/集合上的条件的任何地方使用谓词,以便求值可以得出`true``false`
例如,您可以在这些**实时用例**中使用 prdicates
例如,您可以在这些**实时用例**中使用谓词:
1. 查找在特定日期之后出生的所有孩子
2. 披萨定下特定时间
3. 员工超过一定年龄
2. 特定时间定下的披萨
3. 超过一定年龄的员工
#### Java 谓词类
因此, **java 谓词**似乎很有趣。 让我们更深入。
如我所说,`Predicate`**函数式接口**。 这意味着我们可以在需要谓词的任何地方传递 lambda 表达式。 例如,一种这样的方法是来自 [**流**](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html) 接口的`filter()`方法。
如我所说,`Predicate`**函数式接口**。 这意味着我们可以在需要谓词的任何地方传递 lambda 表达式。 例如,一种这样的方法是来自[**流**](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html)接口的`filter()`方法。
```java
/**
......@@ -87,7 +87,7 @@ public static Predicate<Employee> isAdultMale()
```
#### 2\. 所有女性且年龄在 18 岁以上的员工
#### 2\. 所有年龄在 18 岁以上的女性员工
```java
public static Predicate<Employee> isAdultFemale()
......@@ -107,7 +107,7 @@ public static Predicate<Employee> isAgeMoreThan(Integer age)
```
您可以在需要时构建更多它们。 到目前为止,一切都很好。 到目前为止,我已经在 **EmployeePredicates.java** 中包括了上述 3 种方法:
您可以在需要时构建更多它们。 到目前为止,一切都很好。 到目前为止,我已经在`EmployeePredicates.java`中包括了上述 3 种方法:
```java
package predicateExample;
......@@ -141,7 +141,7 @@ public class EmployeePredicates
```
您会看到我创建了另一个实用程序方法 **filterEmployees()**,以显示 **java 谓词过滤器**。 基本上是使代码整洁并减少重复。 您也可以编写多个谓词来构成**谓词链**,就像在[构建器模式](https://howtodoinjava.com/design-patterns/creational/builder-pattern-in-java/)中所做的那样。
您会看到我创建了另一个实用程序方法`filterEmployees()`,以显示 **java 谓词过滤器**。 基本上是使代码整洁并减少重复。 您也可以编写多个谓词来构成**谓词链**,就像在[构建器模式](https://howtodoinjava.com/design-patterns/creational/builder-pattern-in-java/)中所做的那样。
因此,在此函数中,我们传递`employees`的列表并传递谓词,然后此函数将返回满足**参数谓词**中提到的条件的`employees`的新集合。
......@@ -198,7 +198,7 @@ Output:
1. 他们将您的条件(有时是业务逻辑)转移到中心位置。 这有助于分别对它们进行单元测试。
2. 无需将任何更改复制到多个位置。 Java 谓词改善了代码维护。
3. 代码例如 “ filterEmployees(employees,isAdultFemale())”比编写 if-else 块更具可读性。
3. 代码例如`filterEmployees(employees, isAdultFemale())`”比编写`if-else`块更具可读性。
好的,这些是我在 Java 8 谓词中的想法。 您如何看待此功能? 在评论部分与我们所有人分享。
......@@ -207,4 +207,5 @@ Output:
阅读更多 :
[Java 谓词取反示例](https://howtodoinjava.com/java8/predicate-negate-example/)
[Java 链接谓词 – 逻辑 AND 和逻辑 OR 运算](https://howtodoinjava.com/java8/predicates-logical-operations/)
\ No newline at end of file
......@@ -2,18 +2,18 @@
> 原文: [https://howtodoinjava.com/java8/date-and-time-api-changes-in-java-8-lambda/](https://howtodoinjava.com/java8/date-and-time-api-changes-in-java-8-lambda/)
开发人员社区的很大一部分一直在抱怨**日期和日历类**。 原因很多,例如难以理解,难以使用和不灵活。 Date 类甚至已经过时,并且 Java 文档建议使用`Calendar`类而不是`Date`类。 最重要的是,**日期比较**有很多问题,我过去也遇到过这样的问题。
开发人员社区的很大一部分一直在抱怨**日期和日历类**。 原因很多,例如难以理解,难以使用和不灵活。 `Date`类甚至已经过时,并且 Java 文档建议使用`Calendar`类而不是`Date`类。 最重要的是,**日期比较**有很多问题,我过去也遇到过这样的问题。
![Java 8 date api changes](img/5347ceb4419cb47506024a8b36bf7bc0.png)
展望未来,JAVA 8( [Lambda](//howtodoinjava.com/java8/complete-lambda-expressions-tutorial-in-java/) )有望发布新的日期和时间 API /类( [**JSR-310**](https://java.net/projects/jsr-310/ "jsr-310") ),也称为 **ThreeTen** ,它将仅更改您到目前为止的操作方式。 这的一个关键部分是提供一个新的 API,该 API 显着易于使用且不易出错。
展望未来,JAVA 8([Lambda](//howtodoinjava.com/java8/complete-lambda-expressions-tutorial-in-java/))有望发布新的日期和时间 API / 类([**JSR-310**](https://java.net/projects/jsr-310/ "jsr-310")),也称为 **ThreeTen** ,它将仅更改您到目前为止的操作方式。 这的一个关键部分是提供一个新的 API,该 API 显着易于使用且不易出错。
它将提供一些非常需要的功能,例如:
* 所有关键的公共类都是不可变的并且是线程安全的
* 其他计算领域可以采用的定义的术语和行为
I wrote this post on 15th May 2013\. Now today on 18th Mar 2014, java 8 is finally released and available for early access. I have re-validated and verified all the outputs in post examples. They work like charm as they did in May last year. Only change encountered was in `TemporalAdjuster.java`. Previously it was a class, now it is a **`@FunctionalInterface`**. So, I have corrected the related example and used the class “`TemporalAdjusters.java`“.
我在 2013 年 5 月 15 日撰写了这篇文章。 现在是 2014 年 3 月 18 日,今天终于可以发布 Java 8 了,可以早期使用。 我已经重新验证并验证了示例中的所有输出。 与去年 5 月一样,它们像魔术一样工作。 唯一遇到的更改是在`TemporalAdjuster.java`中。 以前是一个类,现在是`@FunctionalInterface`。 因此,我更正了相关示例,并使用了`TemporalAdjusters.java`类。
```java
Table of Contents
......@@ -31,11 +31,11 @@ References
## 代表本地日期和时区的新类
打算替换 Date 类的新类是`LocalDate``LocalTime``LocalDateTime`
打算替换`Date`类的新类是`LocalDate``LocalTime``LocalDateTime`
#### 本地化
#### `LocalDate`
[LocalDate](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html) 类表示日期。 没有时间或时区的表示。
[`LocalDate`](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html)类表示日期。 没有时间或时区的表示。
```java
LocalDate localDate = LocalDate.now();
......@@ -48,9 +48,9 @@ System.out.println(localDate.plusDays(12).toString()); //2013-05-27
```
#### 当地时间
#### `LocalTime`
[LocalTime](https://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html) 类表示时间。 没有日期或时区的表示。
[`LocalTime`](https://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html)类表示时间。 没有日期或时区的表示。
```java
//LocalTime localTime = LocalTime.now(); //toString() in format 09:57:59.744
......@@ -64,9 +64,9 @@ System.out.println(localTime.NOON); //12:00
```
#### localdateti 至
#### `LocalDateTime`
[LocalDateTime](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html) 类表示日期时间。 没有时区的表示。
[`LocalDateTime`](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html)类表示日期时间。 没有时区的表示。
```java
LocalDateTime localDateTime = LocalDateTime.now();
......@@ -77,7 +77,7 @@ System.out.println(localDateTime.getNano()); //911000000
```
如果您想将日期功能与区域信息一起使用,则 Lambda 会为您提供额外的 3 类,类似于上面的一种,即`OffsetDate``OffsetTime``OffsetDateTime`。 时区偏移可以以“ +05:30”或“欧洲/巴黎”格式表示。 这是通过使用另一个类即`ZoneId`完成的。
如果您想将日期功能与区域信息一起使用,则 Lambda 会为您提供额外的 3 类,类似于上面的一种,即`OffsetDate``OffsetTime``OffsetDateTime`。 时区偏移可以以“`+05:30`”或“`Europe/Paris`”格式表示。 这是通过使用另一个类即`ZoneId`完成的。
```java
OffsetDateTime offsetDateTime = OffsetDateTime.now();
......@@ -97,9 +97,9 @@ System.out.println(zonedDateTime.toString()); //2013-05-15T06:45:45.290+0
## 代表时间戳和持续时间的新类
#### 瞬间
#### `Instant`
为了随时表示特定的时间戳,需要使用的类是 [Instant](https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html) `Instant`类表示精确到纳秒的时间点。 对`Instant`的操作包括与另一个`Instant`的比较以及持续时间的增加或减少。
为了随时表示特定的时间戳,需要使用的类是[`Instant`](https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html)`Instant`类表示精确到纳秒的时间点。 对`Instant`的操作包括与另一个`Instant`的比较以及持续时间的增加或减少。
```java
Instant instant = Instant.now();
......@@ -110,9 +110,9 @@ System.out.println(instant.minusSeconds(10).toString()); //2013-05-15T05:19:5
```
#### 持续时间
#### `Duration`
[持续时间](https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html)类是用 Java 语言首次带来的全新概念。 它表示两个时间戳之间的时差。
[`Duration`](https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html)类是用 Java 语言首次带来的全新概念。 它表示两个时间戳之间的时差。
```java
Duration duration = Duration.ofMillis(5000);
......@@ -134,9 +134,9 @@ System.out.println(duration.toString()); //PT10M
`Duration`处理较小的时间单位,例如毫秒,秒,分钟和小时。 它们更适合与应用程序代码进行交互。
####
#### `Period`
要与人互动,您需要获得更大的持续时间,并以 [Period](https://docs.oracle.com/javase/8/docs/api/java/time/Period.html) class 给出。
要与人互动,您需要获得更大的持续时间,并以[`Period`](https://docs.oracle.com/javase/8/docs/api/java/time/Period.html)给出。
```java
Period period = Period.ofDays(6);
......@@ -153,9 +153,9 @@ System.out.println(period.toString()); //P1M29D
## 在现有枚举上添加了实用程序类
当前的 Java SE 平台使用 int 常量表示月份,星期几和 am-pm 等。现在,添加了许多额外的实用程序类,它们在这些枚举的基础上起作用。 我以这样的类为例: [DayOfWeek](https://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html) 。 该类是 day 枚举的包装,并且可以与其他类一致使用。
当前的 Java SE 平台使用`int`常量表示月份,星期几和上午下午等。现在,添加了许多额外的实用程序类,它们在这些枚举的基础上起作用。 我以这样的类为例:[`DayOfWeek`](https://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html)。 该类是每周日期枚举的包装,并且可以与其他类一致使用。
#### 日间周
#### `DayOfWeek`
```java
//day-of-week to represent, from 1 (Monday) to 7 (Sunday)
......@@ -190,7 +190,7 @@ System.out.println(nextTue.toString()); //2013-05-21
## 创建日期对象
现在也可以使用[构建器模式](//howtodoinjava.com/design-patterns/creational/builder-pattern-in-java/)创建日期对象。 构建器模式允许使用单个零件来构建您想要的对象。 这是通过使用以“ at”为前缀的方法来实现的。
现在也可以使用[构建器模式](//howtodoinjava.com/design-patterns/creational/builder-pattern-in-java/)创建日期对象。 构建器模式允许使用单例来构建您想要的对象。 这是通过使用以`at`为前缀的方法来实现的。
```java
//Builder pattern used to make date object
......@@ -231,9 +231,9 @@ System.out.println(forwardedClock.instant().toString()); //2013-05-15T06:30Z
## 时区变更
与时区相关的处理由 3 个主要类别完成。 这些是 [ZoneOffset](https://docs.oracle.com/javase/8/docs/api/java/time/ZoneOffset.html)[TimeZone](https://docs.oracle.com/javase/8/docs/api/java/util/TimeZone.html)[ZoneRules](https://docs.oracle.com/javase/8/docs/api/java/time/zone/ZoneRules.html)
与时区相关的处理由 3 个主要类别完成。 这些是[`ZoneOffset`](https://docs.oracle.com/javase/8/docs/api/java/time/ZoneOffset.html)[`TimeZone`](https://docs.oracle.com/javase/8/docs/api/java/util/TimeZone.html)[`ZoneRules`](https://docs.oracle.com/javase/8/docs/api/java/time/zone/ZoneRules.html)
* `ZoneOffset`类表示与 UTC 的固定偏移量,以秒为单位。 通常以“±hh:mm”格式的字符串表示。
* `ZoneOffset`类表示与 UTC 的固定偏移量,以秒为单位。 通常以`±hh:mm`格式的字符串表示。
* `TimeZone`类表示在其中定义了指定时区规则的区域的标识符。
* `ZoneRules`是定义区域偏移量何时更改的实际规则集。
......@@ -244,7 +244,7 @@ System.out.println(ZoneRules.of(ZoneOffset.of(&quot;+02:00&quot;)).isFixedOffset
```
## 日期格式
## 日期格式
日期格式化通过两个类别(主要是`DateTimeFormatterBuilder``DateTimeFormatter`)支持。 `DateTimeFormatterBuilder`使用构建器模式来构建自定义模式,因为`DateTimeFormatter`为此提供了必要的输入。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册