欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JDK1.8中的Lambda公式--02【Optional】

程序员文章站 2022-06-04 19:20:43
...
1.使用只有一个方法的接口来表示某特定方法并反复使用, 是很早就有的习惯。 使用 Swing编写过用户界面的人对这种方式都不陌生, 例 2-2 中的用法也是如此。 这里无需再标新立异, Lambda 表达式也使用同样的技巧, 并将这种接口称为函数接口。 
表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                          求两个数的乘积( *)

[email protected] 注释

 该注释会强制 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 中可能为空的值文档化, 这比阅读实现代码要简单很多。