JDK1.8中的Lambda公式--02【Optional】
表2-1 Java中重要的函数接口
接口 参数 返回类型 示例
Predicate<T> T boolean 这张唱片已经发行了吗
Consumer<T> T void 输出一个值
Function<T,R> T R 获得 Artist 对象的名字
Supplier<T> None T 工厂方法
UnaryOperator<T> T T 逻辑非( !)
BinaryOperator<T> (T, T) T 求两个数的乘积( *)
该注释会强制 javac 检查一个接口是否符合函数接口的标准。 如果该注释添加给一个枚举类型、 类或另一个注释, 或者接口包含不止一个抽象方法, javac 就会报错。 重构代码时,使用它能很容易发现问题。
3.三定律
如果对默认方法的工作原理, 特别是在多重继承下的行为还没有把握, 如下三条简单的定律可以帮助大家。
1. 类胜于接口。 如果在继承链中有方法体或抽象的方法声明, 那么就可以忽略接口中定义的方法。
2. 子类胜于父类。 如果一个接口继承了另一个接口, 且两个接口都定义了一个默认方法,那么子类中定义的方法胜出。
3. 没有规则三。 如果上面两条规则不适用, 子类要么需要实现该方法, 要么将该方法声明为抽象方法。
其中第一条规则是为了让代码向后兼容。
4.Optional
//①创建某个值的 Optional 对象
Optional<String> a=Optional.of("a");
System.out.println(a.get());
//②创建一个空的 Optional 对象, 并检查其是否有值
Optional<String> b =Optional.empty();
System.out.println(b.isPresent());
Optional<String> c =Optional.ofNullable(null);
System.out.println(c.isPresent());
//③使用 orElse 和 orElseGet 方法
System.out.println(Objects.equals("b", b.orElse("b")));
System.out.println(Objects.equals("c", c.orElseGet(()->"c")));
5.练习题(1) 在例 4-25 所示的 Performance 接口基础上, 添加 getAllMusicians 方法, 该方法返回包含所有艺术家名字的 Stream, 如果对象是乐队, 则返回每个乐队成员的名字。 例如, 如果 getMusicians 方法返回甲壳虫乐队, 则 getAllMusicians 方法返回乐队名和乐队成员,如约翰 · 列侬、 保罗 · 麦卡特尼等。
例 4-25 表示音乐表演的接口
// 该接口表示艺术家的演出— — 专辑或演唱会
public interface Performance {
public String getName();
public Stream<Artist> getMusicians();
}
答案:
service:
package com.cmbcc.service;
import java.util.stream.Stream;
import com.cmbcc.model.Artist;
public interface Performance {
public String getName();
public Stream<Artist> getMusicians();
public Stream<String> getAllMusicians();
}
serviceImpl
package com.cmbcc.service.impl;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
import com.cmbcc.model.Artist;
import com.cmbcc.service.Performance;
public class PerformanceImpl implements Performance{
private List<Artist> musicians;
private String artistName;
public void setName(String artistName) {
this.artistName = artistName;
}
public void setMusicians(List<Artist> musicians) {
this.musicians = musicians;
}
@Override
public String getName() {
return artistName;
}
@Override
public Stream<Artist> getMusicians() {
return musicians.stream()
.filter(artist->Objects.equals(artist.getName(), artistName));
}
@Override
public Stream<String> getAllMusicians() {
Stream<Artist> musicians =getMusicians();
return musicians.map(artist->artist.getName()+""+artist.getMembers());
}
}
测试方法
package com.cmbcc.test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.cmbcc.model.Artist;
import com.cmbcc.service.impl.PerformanceImpl;
public class Test_05 {
public static void main(String[] args) {
List<Artist> musicians=new ArrayList<Artist>();
musicians.add(new Artist("JiaKeChong",Arrays.asList("zhangsan","lisi","wangwu") , "Americ"));
musicians.add(new Artist("TFBOYS",Arrays.asList("wangyuan","wang","yiyangqianxi") , "China"));
musicians.add(new Artist("xiha",Arrays.asList("lili","tom") , "Italy"));
musicians.add(new Artist("yangmi",null , "Italy"));
PerformanceImpl impl=new PerformanceImpl();
impl.setMusicians(musicians);
impl.setName("JiaKeChong");
System.out.println(impl.getAllMusicians().collect(Collectors.toList()));
}
}
(2) 例 4-26 所示的 Artists 类表示了一组艺术家, 重构该类, 使得 getArtist 方法返回一个 Optional<Artist> 对象。 如果索引在有效范围内, 返回对应的元素, 否则返回一个空Optional 对象。 此外, 还需重构 getArtistName 方法, 保持相同的行为。例 4-26 包含多个艺术家的 Artists 类
例
public class Artists {
private List<Artist> artists;
public Artists(List<Artist> artists) {
this.artists = artists;
}
public Artist getArtist(int index) {
if (index < 0 || index >= artists.size()) {
indexException(index);
}
return artists.get(index);
}
private void indexException(int index) {
throw new IllegalArgumentException(index +
"doesn't correspond to an Artist");
}
public String getArtistName(int index) {
try {
Artist artist = getArtist(index);
return artist.getName();
} catch (IllegalArgumentException e) {
return "unknown";
}
}
}
答案:
package com.cmbcc.model;
import java.util.List;
import java.util.Optional;
public class Artists {
private List<Artist> artists;
public Artists(List<Artist> artists) {
this.artists = artists;
}
public Optional<Artist> getArtist(int index) {
if (index < 0 || index >= artists.size()) {
indexException(index);
return Optional.empty();
}
return Optional.of(artists.get(index));
}
private void indexException(int index) {
throw new IllegalArgumentException(index + "doesn't correspond to an Artist");
}
public String getArtistName(int index) {
try {
Optional<Artist> artist = getArtist(index);
return artist.get().getName();
} catch (IllegalArgumentException e) {
return "unknown";
}
}
}
总结:
Optional 是为核心类库新设计的一个数据类型, 用来替换 null 值。 人们对原有的 null 值有很多抱怨, 甚至连发明这一概念的 Tony Hoare 也是如此, 他曾说这是自己的一个“ 价值连城的错误”。 作为一名有影响力的计算机科学家就是这样: 虽然连一毛钱也见不到, 却也可以犯一个“ 价值连城的错误”。
人们常常使用 null 值表示值不存在, Optional 对象能更好地表达这个概念。 使用 null 代表值不存在的最大问题在于表值不存在的最大问题在于 NullPointerException。 一旦引用一个存储 null 值的变量, 程序会立即崩溃。 使用 Optional 对象有两个目的: 首先, Optional 对象鼓励程序员适时检查变量是否为空, 以避免代码缺陷; 其次, 它将一个类的 API 中可能为空的值文档化, 这比阅读实现代码要简单很多。