Java8实战之(七)重构、测试、调试

7 重构、测试、调试

在这里插入图片描述

7.1 为改善可读性和灵活性重构代码

在这里插入图片描述

7.1.1 改善代码的可读性

在这里插入图片描述
跟之前的版本相比较,Java8的新特性也可以帮助提升代码的可读性
(1)使用java8,可以减少冗长的代码,让代码更容易理解
(2)通过Stream和方法引用,你的代码将变得更直观
以下介绍三种简单的重构

  1. 重构代码,用lamdba表达式重构匿名类
  2. 用方法引用重构Lamdba表达式
  3. 用StreamApi重构命令式的数据处理

7.1.2 从匿名类到Lamdba表达式

在这里插入图片描述

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("你是猪");
            }
        };
        runnable.run();

        Runnable runnable1 = () ->{
            System.out.println("你是1");
        };
        runnable1.run();

应该注意一下两种情况

1.匿名类和Lamdba表达式中的this和super的含义不同。
在匿名类中的this是类自身,但是在Lamdba中是包含类
2.匿名类可以屏蔽包含类的变量,而Lamdba表达式不能(会导致变异错误),比如以下代码

  int a= 10;
        Runnable runnable1 = () ->{
            int a = 2;
            System.out.println("你是1");
        };
        runnable1.run();

在这里插入图片描述
在这里插入图片描述

7.1.3 从Lamdba表达式到方法引用的转换

简单来说就是Lamdba的返回体封装成方法直接调用
在这里插入图片描述

    Map<CaloricLevel, List<Dish>> dishesByCaloricLevel =
                menu.stream()
                        .collect(
                                groupingBy(dish -> {
                                    if (dish.getCalories() <= 400) return CaloricLevel.DIET;
                                    else if (dish.getCalories() <= 700) return CaloricLevel.NORMAL;
                                    else return CaloricLevel.FAT;
                                }));

在这里插入图片描述

public static void test(List<Dish> menu){
        Map<CaloricLevel, List<Dish>> dishesByCaloricLevel =
                menu.stream()
                        .collect(
                                groupingBy(Task::getLevel));
    }

    public static CaloricLevel getLevel(Dish dish){
        if (dish.getCalories() <= 400) {
            return CaloricLevel.DIET;
        }
        else if (dish.getCalories() <= 700) {
            return CaloricLevel.NORMAL;
        }
        else {
            return CaloricLevel.FAT;
        }
    }

在这里插入图片描述

7.1.4 从命令式的数据处理切换到Stream

在这里插入图片描述
在这里插入图片描述

7.1.5 增加代码的灵活性

在这里插入图片描述
1.采用函数接口
在这里插入图片描述
2.有条件的延迟执行
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3.环绕执行
在这里插入图片描述


/**
 * 函数式接口
 */
@FunctionalInterface
public interface BufferedReaderProcessor {
    String process(BufferedReader bufferedReader) throws Exception;

}
 // 现在你就可以把这个接口作为新的processFile方法的参数了:
    public static String processFile(BufferedReaderProcessor bufferedReaderProcessor){
        try {
            BufferedReader bufferedReader = new BufferedReader(new FileReader("E:\\learn\\java8-master\\java8\\src\\main\\resources\\data.txt"));
            return bufferedReaderProcessor.process(bufferedReader);
        }catch (Exception ex){
            System.out.println("异常");
        }
        return null;
    }
        String twoLine = processFile((BufferedReader br)-> br.readLine() + br.readLine());

在这里插入图片描述

7.2 使用Lamdba重构面向对象的设计模式

在这里插入图片描述

  1. 策略模式
  2. 模板方法
  3. 观察者模式
  4. 责任链模式
  5. 工厂模式
    我们通过Lamdba来解决上述设计模式所要解决的问题

7.2.1 策略模式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
使用Lamdba表达式
在这里插入图片描述

package com.java.lamdba.seven;

public interface ValidationStrategy {
    boolean execute(String s);

    public static void main(String[] args) {
        Validator numericValidator = new Validator(new IsNumeric());
        boolean b1 = numericValidator.validate("aaaa");
        Validator lowerCaseValidator = new Validator(new IsAllLowerCase ());
        boolean b2 = lowerCaseValidator.validate("bbbb");

        Validator test = new Validator((String s) -> s.matches("[a-z]+"));
        Validator test2 = new Validator((String s) -> s.matches("\\d+"));
        test.validate("aaa");
        test2.validate("asdasd");

    }
}
class IsAllLowerCase implements ValidationStrategy {
    @Override
    public boolean execute(String s){
        return s.matches("[a-z]+");
    }
}
class IsNumeric implements ValidationStrategy {
    @Override
    public boolean execute(String s){
        return s.matches("\\d+");
    }
}
class Validator{
    private final ValidationStrategy strategy;
    public Validator(ValidationStrategy v){
        this.strategy = v;
    }
    public boolean validate(String s){
        return strategy.execute(s);
    }
}

在这里插入图片描述

7.2.2 模板方法

在这里插入图片描述

abstract class OnlineBanking { 
	public void processCustomer(int id){ 
	 Customer c = Database.getCustomerWithId(id); 
	 makeCustomerHappy(c); 
}
  abstract void makeCustomerHappy(Customer c); 
 }

在这里插入图片描述
之前模板方法的重构

package com.learn.designmode.mode.template.demo;

import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 账户类
 */
public abstract class Account {

    /** 基本方法-具体方法
     * @param account
     * @param password
     * @return
     */
    public boolean validate(String account,String password){
        System.out.println("账号" + account);
        System.out.println("密码" + password);
        if ("张无忌".equals(account) && "123456".equals(password)){
            return true;
        }else {
            return false;
        }
    }

    /**
     * 基本方法-抽象方法
     */
    public abstract void calculateInterest();

    public void display(){
        System.out.println("显示利息");
    }

    /** 模板方法
     * @param account
     * @param password
     */
    public void handle(String account,String password){
        if (!validate(account,password)){
            System.out.println("账号密码错误");
            return;
        }
        calculateInterest();
        display();
    }


    /** 模板方法(使用Lamdba重构)
     * @param account
     * @param password
     */
    public void handle(String account, String password, Supplier supplier){
        if (!validate(account,password)){
            System.out.println("账号密码错误");
            return;
        }
        // calculateInterest 替换成Lamdba

        //calculateInterest();
        supplier.get();
        display();
    }
}


package com.learn.designmode.mode.template.demo;

import com.learn.designmode.utils.XMLUtil;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;

public class Client {
    public static void main(String[] args) throws SAXException, IllegalAccessException, IOException, InstantiationException, ParserConfigurationException, ClassNotFoundException {
        Account account = (Account) XMLUtil.getBean("template");
        //account.handle("张无忌","123456");

        new Account() {
            @Override
            public void calculateInterest() {

            }
        }.handle("张无忌","12345612312",() ->{
            System.out.println("显示Lamdba");
            return null;
        });
    }
}

7.2.3 观察者模式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
使用Lamdba
在这里插入图片描述

package com.java.lamdba.seven;

import java.util.ArrayList;
import java.util.List;

public interface Observer {
    void notify(String tweet);

    public static void main(String[] args) {
        Feed f = new Feed();
        // 普通的注入观察者
        f.registerObserver(new Guardian());
        
        // 使用Lambda注入观察者
        f.registerObserver((String tweet) -> {
            if(tweet != null && tweet.contains("money")){
                System.out.println("Breaking news in NY! " + tweet);
            }
        });
        f.registerObserver((String tweet) -> {
            if(tweet != null && tweet.contains("queen")){
                System.out.println("Yet another news in London... " + tweet);
            }
        });
        f.notifyObservers("The queen said her favourite book is Java 8 in Action!");
    }
}

class NYTimes implements Observer{
    @Override
    public void notify(String tweet) {
        if(tweet != null && tweet.contains("money")){
            System.out.println("Breaking news in NY! " + tweet);
        }
    }
}
class Guardian implements Observer{
    @Override
    public void notify(String tweet) {
        if(tweet != null && tweet.contains("queen")){
            System.out.println("Yet another news in London... " + tweet);
        }
    }
}
class LeMonde implements Observer{
    @Override
    public void notify(String tweet) {
        if(tweet != null && tweet.contains("wine")){
            System.out.println("Today cheese, wine and news! " + tweet);
        }
    }
}
interface Subject{
    void registerObserver(Observer o);
    void notifyObservers(String tweet);
}

class Feed implements Subject{
    private final List<Observer> observers = new ArrayList<>();
    @Override
    public void registerObserver(Observer o) {
        this.observers.add(o);
    }
    @Override
    public void notifyObservers(String tweet) {
        observers.forEach(o -> o.notify(tweet));
    }
}

7.2.4 责任链模式

在这里插入图片描述

package com.java.lamdba.seven;

public abstract class ProcessingObject<T> {

    protected ProcessingObject<T> successor;
    public void setSuccessor(ProcessingObject<T> successor){
        this.successor = successor;
    }
    public T handle(T input){
        T r = handleWork(input);
        if(successor != null){
            return successor.handle(r);
        }
        return r;
    }
    abstract protected T handleWork(T input);
}

在这里插入图片描述
在这里插入图片描述
使用Lamdba表达式
在这里插入图片描述

package com.java.lamdba.seven;

import java.util.function.Function;
import java.util.function.UnaryOperator;

public abstract class ProcessingObject<T> {
    public static void main(String[] args) {
        ProcessingObject<String> p1 = new HeaderTextProcessing();
        ProcessingObject<String> p2 = new SpellCheckerProcessing();
        p1.setSuccessor(p2);
        String result = p1.handle("Aren't labdas really sexy?!!");
        System.out.println(result);


        UnaryOperator<String> headerProcessing =
                (String text) -> "From Raoul, Mario and Alan: " + text;
        UnaryOperator<String> spellCheckerProcessing =
                (String text) -> text.replaceAll("labda", "lambda");
        Function<String, String> pipeline =
                headerProcessing.andThen(spellCheckerProcessing);
        String result2 = pipeline.apply("Aren't labdas really sexy?!!");
    }

    protected ProcessingObject<T> successor;
    public void setSuccessor(ProcessingObject<T> successor){
        this.successor = successor;
    }
    public T handle(T input){
        T r = handleWork(input);
        if(successor != null){
            return successor.handle(r);
        }
        return r;
    }
    abstract protected T handleWork(T input);
}
class HeaderTextProcessing extends ProcessingObject<String> {
    @Override
    public String handleWork(String text){
        return "From Raoul, Mario and Alan: " + text;
    }
}
class SpellCheckerProcessing extends ProcessingObject<String> {
    @Override
    public String handleWork(String text){
        return text.replaceAll("labda", "lambda");
    }
}

7.2.5 工厂模式

在这里插入图片描述

package com.java.lamdba.seven;

public class ProductFactory {

    public static Product createProduct(String name){
        switch(name){
            case "loan": return new Loan();
            case "stock": return new Stock();
            case "bond": return new Bond();
            default: throw new RuntimeException("No such product " + name);
        }
    }
}
class Product{
    
}
class Loan extends Product{

}
class Stock extends Product{

}
class Bond extends Product{
    
}

使用Lamdba
在这里插入图片描述
在这里插入图片描述

package com.java.lamdba.seven;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

public class ProductFactory {

    final static Map<String, Supplier<Product>> map = new HashMap<>();
    static {
        map.put("loan", Loan::new);
        map.put("stock", Stock::new);
        map.put("bond", Bond::new);
    }
    public static void main(String[] args) {
        Supplier<Product> loanSupplier = Loan::new;
        Loan loan = (Loan) loanSupplier.get();
        System.out.println("aa");
    }

    public static Product createProduct(String name){
        switch(name){
            case "loan": return new Loan();
            case "stock": return new Stock();
            case "bond": return new Bond();
            default: throw new RuntimeException("No such product " + name);
        }
    }
}
class Product{

}
class Loan extends Product{

}
class Stock extends Product{

}
class Bond extends Product{

}

7.3 测试Lamdba表达式

在这里插入图片描述

package com.java.lamdba.seven;

import org.junit.Test;

import static junit.framework.TestCase.assertEquals;

public class Point {
    private final int x;
    private final int y;
    private Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public int getX() { return x; }
    public int getY() { return y; }
    public Point moveRightBy(int x){
        return new Point(this.x + x, this.y);
    }

    @Test
    public void testMoveRightBy() throws Exception {
        Point p1 = new Point(5, 5);
        Point p2 = p1.moveRightBy(10);
        assertEquals(15, p2.getX());
        assertEquals(5, p2.getY());
    }
}

7.3.1 测试可见的Lamdba函数行为

在这里插入图片描述

    public final static Comparator<Point> compareByXAndThenY =
            comparing(Point::getX).thenComparing(Point::getY);
    @Test
    public void testComparingTwoPoints() throws Exception {
        Point p1 = new Point(10, 15);
        Point p2 = new Point(10, 20);
        int result = Point.compareByXAndThenY.compare(p1 , p2);
        assertEquals(-1, result);
    }

7.3.2 测试使用Lamdba的方法的行为

在这里插入图片描述
在这里插入图片描述

  public static List<Point> moveAllPointsRightBy(List<Point> points, int x){
        return points.stream()
                .map(p -> new Point(p.getX() + x, p.getY()))
                .collect(toList());
    }

    @Test
    public void testMoveAllPointsRightBy() throws Exception{
        List<Point> points =
                Arrays.asList(new Point(5, 5), new Point(10, 5));
        List<Point> expectedPoints =
                Arrays.asList(new Point(15, 5), new Point(20, 5));
        List<Point> newPoints = Point.moveAllPointsRightBy(points, 10);
        assertEquals(expectedPoints, newPoints);
    }

7.3.3 将复杂的Lamdba表达式分到不同的方法

在这里插入图片描述

7.3.4 高阶函数的测试

在这里插入图片描述

在这里插入图片描述

   @Test
    public void testFilter() throws Exception{
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
        List<Integer> even = filter(numbers, (Integer i) -> i % 2 == 0);
        List<Integer> smallerThanThree = filter(numbers, (Integer i) -> i < 3);
        assertEquals(Arrays.asList(2, 4), even);
        assertEquals(Arrays.asList(1, 2), smallerThanThree);
    }

在这里插入图片描述

7.4 调试

调试有问题的代码时,程序员的兵器库里有两大老式武器,分别是:
(1)查看栈跟踪
(2)输出日志

7.4.1 查看栈跟踪

在这里插入图片描述
Lamdba表达式与栈跟踪
在这里插入图片描述

package com.java.lamdba.seven;

import java.util.Arrays;
import java.util.List;

public class Debugging{
    public static void main(String[] args) {
        List<Point> points = Arrays.asList(new Point(12, 2), null);
        points.stream().map(p -> p.getX()).forEach(System.out::println);
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.4.2 使用日志调试

在这里插入图片描述
在这里插入图片描述

package com.java.lamdba.seven;

import java.util.ArrayList;
import java.util.List;

import static java.util.stream.Collectors.toList;

public class Test {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(1);
        numbers.add(1);
        numbers.add(1);
        numbers.add(1);
        numbers.add(1);
        List<Integer> result =
                numbers.stream()
                        .peek(x -> System.out.println("from stream: " + x))
                        .map(x -> x + 17)
                        .peek(x -> System.out.println("after map: " + x))
                        .filter(x -> x % 2 == 0)
                        .peek(x -> System.out.println("after filter: " + x))
                        .limit(3)
                        .peek(x -> System.out.println("after limit: " + x))
                        .collect(toList());
    }
}

7.5 总结

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/* * 原始需求背景: * 网宿CDN要按月收取客户的服务费用,根据流量的大小、 * 服务的类型等,收取不同的费用,收费规则如下: * web应用:1000元/M * 流媒体应用:1000元/M*0.7 * 下载应用:1000元/M*0.5 * 月末打印报表时,要罗列每个用户每个频道的费用、客户总费用, * 还要打印该客户的重要性指数,重要性指数=网页流/100+下载流量/600; * * 需求变更场景: * 系统已经开发出来了,接下来,运维部门现在希望对系统做一点修改, * 首先,他们希望能够输出xml,这样可以被其它系统读取和处理,但是, * 这段代码根本不可能在输出xml的代码中复用report()的任何行为,唯一 * 可以做的就是重写一个xmlReport(),大量重复report()中的行为,当然, * 现在这个修改还不费劲,拷贝一份report()直接修改就是了。 * 不久,成本中心又要求修改计费规则,于是我们必须同时修改xmlReport() * 和report(),并确保其一致性,当后续还要修改的时候,复制-黏贴的问题就 * 浮现出来了,这造成了潜在的威胁。 * 再后来,客服部门希望修改服务类型和用户重要性指数的计算规则, * 但还没决定怎么改,他们设想了几种方案,这些方案会影响用户的计费规则, * 程序必须再次同时修改xmlReport()和report(),随着各种规则变得越来越复杂, * 适当的修改点越 来越难找,不犯错误的机会越来越少。 * 现在,我们运用所学的OO原则和方法开始进行改写吧。 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值