第八章 重构、测试和调试
为改善可读性和灵活性重构代码
- 改善代码的可读性
- 重构代码,‘合理的’用Lambda表达式取代匿名类
- ‘尽量’用方法引用重构Lambda表达式
- ‘尽量’用Stream API重构命令式的数据处理
- 增加代码的灵活性
- 采用函数接口:应用场景
- 有条件的延迟执行和环绕执行
- 策略模式场景
- 模版方法场景
- 采用函数接口:应用场景
- 使用Lambda重构面向对象的设计模式
- 策略模式:策略模式包含一下部分内容
- 一个代表某个算法的接口
- 一个或多个接口的具体实现
- 一个或多个使用策略对象的客户
- 策略模式:策略模式包含一下部分内容
代码示例见第一部分第二章
- 模版方法
示例:数据库操作伪代码
public void exec(String sql, Consumer<String> consumer){
openCollection();
consumer.accept(sql);
closeCollection();
}
@Test
public void db(){
exec("insert sql",sql -> System.out.println("执行插入操作:"+sql));
exec("select sql",sql -> System.out.println("执行查询操作:"+sql));
exec("delete sql",sql -> System.out.println("执行删除操作:"+sql));
exec("update sql",sql -> System.out.println("执行更新操作:"+sql));
}
- 观察者模式
interface Observer{
void notify(String msg);
}
interface Subject{
void register(Observer observer);
void notifyObservers(String msg);
}
class MessageSubject implements Subject{
private final List<Observer> observers = new ArrayList<>();
@Override
public void register(Observer observe) {
observers.add(observe);
}
@Override
public void notifyObservers(String message) {
observers.forEach(o->o.notify(message));
}
}
@Test
public void subsTest(){
MessageSubject messageSubject = new MessageSubject();
messageSubject.register((message)-> System.out.println("订阅者1:收到消息"+message));
messageSubject.register((message)-> System.out.println("订阅者2:收到消息"+message));
messageSubject.register((message)-> System.out.println("订阅者3:收到消息"+message));
messageSubject.register((message)-> System.out.println("订阅者4:收到消息"+message));
messageSubject.notifyObservers("hello java 8");
}
- 责任链模式
UnaryOperator<String> handler1 = (msg) -> "handler 1 do something:"+msg;
UnaryOperator<String> handler2 = (msg) -> "handler 2 do something:"+msg;
UnaryOperator<String> handler3 = (msg) -> "handler 3 do something:"+msg;
Function<String, String> holder = handler3.andThen(handler2).andThen(handler1);
String result = holder.apply("java 8");
System.out.println(result);
第九章 默认方法
Java8中的接口现在支持在声明方法的同时提供实现,可以通过一下两种方式实现:
- 在接口内声明静态方法
- 默认方法,通过默认方法可以指定接口方法的默认实现
总结:解决了一旦接口发生变化,实现这些接口的类也必须发生变化带来的问题,可以以兼容的方式解决Java类库的演进问题。对于工具辅助类,可以将其迁移到接口中。
- 菱形问题:当实现的接口中包含两个完全一样的默认方法时,需要在实现类中显示的覆盖此方法
第十章 用Optional取代null
- 作用:处理潜在可能缺失的值
- 注意:Optional未实现序列化接口,无法进行序列化相关操作
- 核心方法说明:
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
// 创建一个空的optional对象
public static<T> Optional<T> empty() {
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
// 依据一个非空对象创建一个optional对象,当对象为空时抛出NullPointException
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
// 依据一个可空对象创建一个optional对象
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
// 获取Value,或抛出NoSuchElementException
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
// 校验值是否存在
public boolean isPresent() {
return value != null;
}
// 如果值存在则执行consumer.accept(value);
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
// 如果值存在,则执行mapper函数返回对应值类型的optional对象
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
// 相对于map拆掉了一层Optional
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}
// 如果值存在则返回值,否则返回默认值
public T orElse(T other) {
return value != null ? value : other;
}
// 如果值存在则返回值,否则执行函数返回值
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
// 如果值存在则返回值,否则抛出指定异常
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
}
简单示例:
// 需求:获取用户名称
// 伪代码,从数据库查询一个用户
User user = getOneUser();
// 原始方式
if(null != user){
String name = user.getName();
if(null !=null && name.length()>0){
return name;
}
}
return "unknown user";
// optional 方式
Optional<User> cd = Optional.ofNullable(null);
Optional<String> optional = cd.map(User::getName);
return optional.orElse("unknown user");
总结:Optional操作不是必须的,不使用Optional也能实现同样的需求,但使用Optional会使得代码更加简洁、优雅、易读和维护,有点像是一层语法糖,对需要操作的对象进行了一次“代理”操作。
第十一章 CompletableFuture: 组合式编程
Future接口(Java 5)
Future使用示意图如下: 代码示例:
@Test
public void asyncTest() throws ExecutionException, InterruptedException, TimeoutException {
ExecutorService executor = Executors.newCachedThreadPool();
Future<String> future = executor.submit(()->{
System.out.println("hello future :"+Thread.currentThread().getName());
Thread.sleep(1000);
return "asynchronous exec end";
});
System.out.println("main thread:"+Thread.currentThread().getName());
future.get(2, TimeUnit.SECONDS);
}
CompletableFuture
代码示例:
@Test
public void completableFutureTest() throws Exception{
CompletableFuture<String> completableFuture = new CompletableFuture<>();
ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(()->{
try {
// 耗时操作处理
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("generate result");
completableFuture.complete("async result:: "+Thread.currentThread().getName());
});
try {
// 耗时操作处理
Thread.sleep(1000);
System.out.println("main thread do other thing:"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("try get result");
String s = completableFuture.get();
System.out.println("result: " +s);
}
第十二章 新的日期和时间API
- LocalDate
// 以及已有日期创建
LocalDate of = LocalDate.of(2019, 11, 15);
// 获取当前日志
LocalDate today = LocalDate.now();
// 获取当前年
int year = today.getYear();
// 获取当前月
int monthValue = today.getMonthValue();
// 获取当前月有多少天
int lengthOfMonth = today.lengthOfMonth();
// 获取当前年有多少天
int lengthOfYear = today.lengthOfYear();
// 获取当前是周几
DayOfWeek dayOfWeek = today.getDayOfWeek();
// 获取当前是一年中的第几天
int dayOfYear = today.getDayOfYear();
- LocalTime
// 创建
LocalTime localTime = LocalTime.of(2,34,34);
LocalTime now = LocalTime.now();
int hour = now.getHour();
int minute = now.getMinute();
int second = now.getSecond();
- LocalDate和LocalTime的合体LocalDateTime
- 操作解析和格式化日期
LocalDateTime now = LocalDateTime.now();
// 获取上月的日期 注意:LocalDateTime为不可变对象,下述方法都是重新创建出Local对象
// 方式1
LocalDateTime lastMonthDateTime = now.minusMonths(1);
// 方式2
LocalDateTime lastMonthDateTime2 = now.withMonth(now.getMonthValue() - 1);
// 获取10天以后的日期
LocalDateTime after10DaysTime = now.plusDays(10);
- TemporalAdjusters
LocalDateTime now = LocalDateTime.now();
// 获取当前月第三周的周末
LocalDateTime with = now.with(TemporalAdjusters.dayOfWeekInMonth(3, DayOfWeek.SUNDAY));
// 获取当前月的第一天
LocalDateTime firstDayOfMonth = now.with(TemporalAdjusters.firstDayOfMonth());
// 获取下一月的第一天
LocalDateTime firstDayOfNextMonth = now.with(TemporalAdjusters.firstDayOfNextMonth());
// 获取当前年的第一天
LocalDateTime firstDayOfYear = now.with(TemporalAdjusters.firstDayOfYear());
// 获取下一年的第一天
LocalDateTime firstDayOfNextYear = now.with(TemporalAdjusters.firstDayOfNextYear());
// 获取当前月第一周的周末 等同于 now.with(TemporalAdjusters.dayOfWeekInMonth(1, DayOfWeek.SUNDAY));
LocalDateTime firstInMonth = now.with(TemporalAdjusters.firstInMonth(DayOfWeek.SUNDAY));
// 获取当前月的最后一天
LocalDateTime lastDayOfMonth = now.with(TemporalAdjusters.lastDayOfMonth());
- 格式化输出
LocalDateTime now = LocalDateTime.now();
// 20191115
System.out.println(now.format(DateTimeFormatter.BASIC_ISO_DATE));
// 2019-11-15T17:32:21.605
System.out.println(now.format(DateTimeFormatter.ISO_DATE_TIME));
// 2019-11-15 17:32:21
System.out.println(now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));