自己出的一道java8设计题,让我们一起来学习一下java8的优秀思想
如果你还不熟悉java8的新特性,可以看下下面这篇文章 或者 B站红康师傅讲解的java8新特性,宋红康老师讲的不止有java8哦,乃至java 9-15的新特性都有,可以在B站中找到,或者尚硅谷官网可以免费获取到。
《B站尚硅谷官方运营号地址》
想要了解四大类型(Consumer、Supplier、Predicate、Funtion)接口的看下前置文章:
java8新特性—大总结–建议收藏、点赞、加关注!!!
如果此前已经掌握了java8的新特性,至少lambda表达式是没啥大问题的。
请听题
要求设计一个计算器,其功能是完成两个数的四则运算(加减乘除)。
例如:有两个操作数 a 和 b 都是double类型的。
初级程序员的写法,具有一定的封装思想。
下面代码看起来没有问题,很nice 对吧。
public class Demo {
public static void main(String[] args) {
double a = 12, b = 3, result = 0;
result = Calculator.run("+", a, b);
System.out.println("加法 a + b = "+result); // 调用工具类得到结果
result = Calculator.run("-", a, b);
System.out.println("减法 a - b = "+result);
result = Calculator.run("*", a, b);
System.out.println("乘法 a * b = "+result);
result = Calculator.run("/", a, b);
System.out.println("除法 a / b = "+result);
}
}
/**
* 封装的一个工具类
*/
class Calculator {
/**
* @param operatorString 运算符
* @param a 操作数1
* @param b 操作数2
* @return a,b经过运算符的结果值
*/
public static double run(String operatorString, double a, double b) {
if (operatorString.equals("+")) {
return a + b;
} else if (operatorString.equals("-")) {
return a - b;
} else if (operatorString.equals("*")) {
return a * b;
} else if (operatorString.equals("/")) {
return a / b;
} else {
throw new IllegalArgumentException("非法操作符:" + operatorString);
}
}
}
如果你有一些工作经验了,你会发现像这种if-else
的写法很不好,看起来很不舒服。或许你会想到用switch
进行代替,但依然还是不舒服,因为写在一起,很容易看错,稍微不注意你就会因为这个if-else
埋坑。出现bug就很不好改
如果你之前看过我另外一篇文章,利用enmn
代替if-else
用枚举代替if-else的参考写法
有一定工作经验的程序员写法,利用枚举代替 if-else
import java.util.HashMap;
import java.util.Map;
public class EnmuMode {
private final static Map<String, String> map;
static {
map = new HashMap<>();
map.put("+", "ADD");
map.put("-", "SUBTRACT");
map.put("*", "MULTIPLY");
map.put("/", "DIVIDION");
}
public static void main(String[] args) {
double a = 12, b = 3, result = 0;
String option= "*"; // 运算操作
String strategy = map.getOrDefault(option, "EXCEPTION");// 得到策略字符串
result = CalculateEnum .valueOf(strategy).calculate(leftNum, rightNum);// 根据策略调用得到对应枚举,调用对应的方法得到计算的结果
System.out.println(result); // 打印计算后的结果
}
}
enum CalculateEnum {
ADD {
@Override
public double calculate(double leftNum, double rightNum) {
return leftNum + rightNum;
}
},
SUBTRACT {
@Override
public double calculate(double leftNum, double rightNum) {
return leftNum - rightNum;
}
},
MULTIPLY {
@Override
public double calculate(double leftNum, int rightNum) {
return leftNum * rightNum;
}
},
DIVIDION {
@Override
public double calculate(double leftNum, double rightNum) {
return leftNum / rightNum;
}
},
EXCEPTION {
@Override
public double calculate(double leftNum, double rightNum) {
throw new IllegalArgumentException("运算操作不支持");
}
};
/**
* 将操作数 leftNum,rightNum 运算得到新值
* return 计算后的结果值
*/
double calculate(double leftNum, double rightNum);
}
而java8程序员的写法
定义一个函数式接口,使用lambda表达式完成功能
public class JAVA8Demo {
public static void main(String[] args) {
CalculateImpl calculate = new CalculateImpl(); // 得到计算器的实现类
double a = 12, b = 3;
double result = calculate.test((x, y) -> x + y, a, b);
System.out.println("加法 a+b=" + result);
double result2 = calculate.test((x, y) -> x - y, a, b);
System.out.println("减法 a-b=" + result2);
double result3 = calculate.test((x, y) -> x * y, a, b);
System.out.println("乘法 a*b=" + result3);
double result4 = calculate.test((x, y) -> x / y, a, b);
System.out.println("除法 a/b=" + result4);
}
}
/**
* 封装接口类,用于进行java8的数据流传递
*/
class CalculateImpl {
public double test(Calculate calculate, double a, double b) {
return calculate.run(a, b); // 将计算后的结果值直接返回
}
}
/*定义一个函数式接口*/
interface Calculate {
/**
* 调用方法得到a,b的结果值
*/
double run(double a, double b);
}
熟悉java8源码的程序员写法
利用 java8 已经提供好的一些常用接口代替自己定义的接口Calculate
public class JAVA8Demo {
public static void main(String[] args) {
CalculateImpl calculate = new CalculateImpl();
double a = 12, b = 3;
double result = calculate.test((x, y) -> x + y, a, b);
System.out.println("加法 a+b=" + result);
double result2 = calculate.test((x, y) -> x - y, a, b);
System.out.println("减法 a-b=" + result2);
double result3 = calculate.test((x, y) -> x * y, a, b);
System.out.println("乘法 a*b=" + result3);
double result4 = calculate.test((x, y) -> x / y, a, b);
System.out.println("除法 a/b=" + result4);
}
}
class Calculator {
public double test(BiFunction<Double,Double,Double> biFunction, double a, double b) {
return biFunction.apply(a, b);
}
}
点评一下上面这些写法的优缺点
第一种写法,设计简单,通过传入操作符来判断使用那种运算,通过封装,将if-else
封装好,但缺点也比较明显,if-else
导致代码的可阅读性变差。而且高度耦合。如果要增加求余数等其它运算操作就得直接修改if-else
分支源码,如果功能特别多,那么这个if-else
就特别长,看都不想看的那种。
第二种写法,利用枚举代替if-else
,这种写法会比if-else
的代码阅读性会好一些,这些功能通过构造器被拆分出来,如果也要增加新功能,那么需要增加枚举的构造器,实现抽象方法来完成功能。优点是可以在其它类中复用代码,缺点就也是需要修改源码,具有一定的耦合性,但比第一种好。
第三种写法,利用函数式编程的思想,设计了一个接口,利用接口将计算后的结果值返回,为了进一步的优化,利用CalculateImpl.test()
方法将接口进一步封装,而接口的实现则由lambda
表达式完成。从代码量看出,这种写法的代码是最少的,也意味着java8的代码产出量是最大的。与写法一、写法二相比更具可变性,想要增加什么功能就能增加什么功能,缺点就是代码不容易复用,使用lambda表达式增加的功能不好在其它类中复用。也就是不能同对象.
调用对应方法完成对应功能。
第四种写法,是熟悉java8源码的程序员才会的写法,没看过源码或者没见过这种写法的是不会想到这样写。
第四种写法引发了一个问题,你熟悉java8的源码?你知道java8提供了哪些常用函数式接口吗?
也就是下面这张截图,这些接口你知道怎么灵活使用?
本文地址:https://blog.csdn.net/qq_41813208/article/details/110791665