使用Java 8中的`map`来处理`Optional.Empty()`。

huangapple go评论57阅读模式
英文:

Use Java8 map over Optional.Empty()

问题

我有一段代码其中我正在做如下操作

```java
Optional<College> college = Optional.ofNullable(student)
        .map(stud ->  stud.getCollege())
        .get()
        .stream()
        .filter(college -> Objects.nonNull(college.getCollegeName()))
        .findFirst();

现在,在编写单元测试时,我遇到了一个问题,如果student为null怎么办?

它将有效地变成:

Optional.empty()                         // 与student为null相同
        .map(stud -> stud.getCollege())
        .get()
        .stream()
        .filter(college -> Objects.nonNull(college.getCollegeName()))
        .findFirst();

我认为这不好,因为我得到了异常

expected<com.src.exceptions.CollegeNotFoundException> but
was<java.util.NoSuchElementException>

#更新

为了澄清问题详情

  1. 是的,stud.getCollege()返回一个list<>

<details>
<summary>英文:</summary>

I have a piece of code where am doing something like:

```java
Optional&lt;College&gt; college = Optional.ofNullable(student)
        .map(stud -&gt;  stud.getCollege())
        .get()
        .stream()
        .filter(college -&gt; Objects.nonNull(college.getCollegeName()))
        .findFirst();

Now, while writing an unit test, I got a catch that what if student comes as null?

It would be effectively like:

Optional.empty()                         // the same as the student is null
        .map(stud -&gt; stud.getCollege())
        .get()
        .stream()
        .filter(college -&gt; Objects.nonNull(college.getCollegeName()))
        .findFirst();

Which I think is not fine because I am getting Exception

expected&lt;com.src.exceptions.CollegeNotFoundException&gt; but
was&lt;java.util.NoSuchElementException&gt;

#Update

Updating the question details for clarifications

  1. Yes stud.getCollege() returns a list<>

答案1

得分: 3

我同意@Nikolas的方法,除非你不应该返回null,在最后返回null违反了使用Optional。对于这个代码片段,可以翻译如下:

Optional<College> optional = Optional.ofNullable(student)
    .map(stud -> stud.getCollegeList())
    .orElse(Collections.emptyList())
    .stream()
    .filter(c -> Objects.nonNull(c.getCollegeName()))
    .findFirst();
英文:

I agree with @Nikolas approach except that you should not return null, returning null at last is against using Optional
What about this one:

Optional&lt;College&gt; optional = Optional.ofNullable(student)
                .map(stud -&gt; stud.getCollegeList())
                .orElse(Collections.emptyList())
                .stream()
                .filter(c -&gt; Objects.nonNull(c.getCollegeName()))
                .findFirst();

答案2

得分: 1

使用没有先前检查 Optional::isPresent 的方式调用 Optional::get 是危险的,因为它可能会产生 CollegeNotFoundException。这也不是使用 Optional 的正确方式。Optional 的理念是在映射/筛选值并在 Optional 最终为空(空)时提供一个默认值。

假设 Student::getCollege 返回 List<College>,其中有一个方法 College::getCollegeName,你可以这样做:

College college = Optional.ofNullable(student)
    .map(stud -> stud.getCollege())
    // 如果 Optional 为空,则使用一个空集合
    .orElse(Collections.emptyList())                              
    .stream()
    .filter(c -> Objects.nonNull(c.getCollegeName())) 
    .findFirst()
    // 获取值,否则 college 为 null 
    .orElse(null);

只要 stud.getCollege() 返回 nullOptional 就会变为空,然后将会流式处理一个空列表。再次应用相同的原则:只要列表为空,就不会调用 filterfindFirst,安全地返回 null(或者你希望的任何默认值)。

还请注意,.filter(c -> Objects.nonNull(c.getCollegeName())) 这一行可能也会产生 NullPointerException,只要不能保证 stud.getCollege() 不会返回带有 null 元素的列表(请记住,列表本身不为 null,所以 Optional 将其视为一个有价值的项)。安全的代码实际上看起来像这样:

Optional<College> college = Optional.ofNullable(student)
    .map(stud -> stud.getCollege())
    .orElse(Collections.emptyList())
    .stream()
    .filter(c -> c != null && c.getCollegeName() != null)
    .findFirst();

实际上,我更喜欢返回 null 对象、nullOptional 本身。

英文:

Calling Optional::get with no previous check Optional::isPresent is dangerous because it might produce CollegeNotFoundException. And it is not the way the Optional shall be used. The idea of Optional is mapping/filtering the values and providing a default value if the Optional ends up with no element (empty).

Assuming Student::getCollege returns List&lt;College&gt; having method College::getCollegeName, you can do the following:

College college = Optional.ofNullable(student)
	.map(stud -&gt; stud.getCollege())
     // if Optional is empty, then use an empty collection
	.orElse(Collections.emptyList())                              
	.stream()
	.filter(c -&gt; Objects.nonNull(c.getCollegeName())) 
	.findFirst()
     // get the value or else college is null 
	.orElse(null);

As long as stud.getCollege() returns null, the Optional becomes empty and an empty list will be streamed. And again the same principle is applied: As long as the list is empty, the filter and findFirst are not be called and null is safely returned (or any default value you wish).

Also note that the line .filter(c -&gt; Objects.nonNull(c.getCollegeName())) might also produce NullPointerException as long as there is not guaranteed stud.getCollege() doesn't return a list with a null element (remember the list is not null itself so Optional treats it as a "valuable" item). The safe code actually looks like:

Optional&lt;College&gt; college = Optional.ofNullable(student)
	.map(stud -&gt; stud.getCollege())
	.orElse(Collections.emptyList())
	.stream()
	.filter(c -&gt; c != null &amp;&amp; c.getCollegeName() != null)
	.findFirst();

Actually, I prefer to return either a null-object, null or Optional itself.

huangapple
  • 本文由 发表于 2020年7月28日 00:28:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/63119484.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定