一段代码被老大要求重构了六次,我心态崩了(1)

List result = new ArrayList<>();

for (Melon melon: melons) {

if (melon != null && melon.getWeight() == weight) {

result.add(melon);

}

}

return result;

}

public static void main(String[] args) {

ArrayList melons = new ArrayList<>();

melons.add(new Melon(“羊角蜜”, 1, “泰国”));

melons.add(new Melon(“西瓜”, 2, “三亚”));

melons.add(new Melon(“黄河蜜”, 3, “兰州”));

List melonType = Filters.filterMelonByType(melons, “黄河蜜”);

melonType.forEach(melon->{

System.out.println(“瓜类型:”+melon.getType());

});

List melonWeight = Filters.filterMelonByWeight( melons,3);

melonWeight.forEach(melon->{

System.out.println(“瓜重量:”+melon.getWeight());

});

}

程序员最喜欢的方式,CV搞定,哈哈。但是我发现filterByWeight()与   filterByType() 非常相似,就是过滤条件不同。我心想,老大不会让我写一个按类型和重量筛选瓜类吧。拿着我的代码去给老大看,果不其然,怕什么来什么???。

第三次 按类型和重量筛选瓜类


为了满足完成老大的任务,我将上面的代码进行了糅合,很快写了如下的代码

/**

* 按照类型和重量来筛选瓜类

* @param melons

* @param type

* @param weight

* @return

*/

public static List filterMelonByTypeAndWeight(List melons, String type, int weight) {

List result = new ArrayList<>();

for (Melon melon: melons) {

if (melon != null && type.equalsIgnoreCase(melon.getType()) && melon.getWeight() == weight) {

result.add(melon);

}

}

return result;

}

老大看了我的代码说,看来你还是没有理解我的意思。假如今天不光我,还有客户继续这样提需求。

那么   Filters 将会有很多这样类似的方法,也就是说写了很多样板代码(代码冗余但又不得不写);

在我们程序员看来,这是不能接受的。如果继续添加新的过滤条件,则代码将变得难以维护且容易出错。你去了解一下lambda表达式函数式接口知识点,再修改一下你的代码。我已经确定了,他就是和我过不去???

第四次 将行为作为参数传递


经过上面的三番折腾。我发现理论上Melon类的任何属性都有可能作为过滤条件,这样的话我们的Filter类将会有大量的样板代码,而且有些方法会非常复杂。

其实我们可以发现,我们每写一个方法,都对应一种查询行为,查询行为必然对应一种过滤条件。有没有办法我们写一个方法,将查询行为作为参数传递进去,从而返回我们的结果呢?

那么给它取了一个名字:行为参数化,在下图中进行了说明(左侧显示了我们现在拥有的;右侧显示了我们想要的),有没有发现样板代码会明显减少???

如果我们将过滤条件视为一种行为,那么将每种行为视为接口的实现是非常直观的。经过分析我们发现以上所有这些行为都有一个共同点:过滤条件boolean 类型的返回   。抽象一个接口如下

public interface MelonPredicate {

boolean test(Melon melon);

}

例如,过滤 黄河蜜可以这样写: HHMMelonPredicate

public class HHMMelonPredicate implements MelonPredicate {

@Override

public boolean test(Melon melon) {

return “黄河蜜”.equalsIgnoreCase(melon.getType());

}

}

以此类推,我们也可以过滤一定重量的瓜:

public class WeightMelonPredicate implements MelonPredicate {

@Override

public boolean test(Melon melon) {

return melon.getWeight() > 5000;

}

}

其实熟悉设计模式的同学应该知道这就是:策略设计模式

主要思想就是让系统在运行时动态选择需要调用的方法。所以我们可以认为   MelonPredicate 接口统一了所有专用于筛选瓜类的算法,并且每种实现都是一种策略,我们也可以把它理解为一种行为。

目前,我们利用策略设计模式,将查询行为进行了抽象。我们还需要一个方法接收   MelonPredicate 参数。于是我定义了  filterMelons() 方法,如下所示:

public static List filterMelons(List melons, MelonPredicate predicate) {

List result = new ArrayList<>();

for (Melon melon: melons) {

if (melon != null && predicate.test(melon)) {

result.add(melon);

}

}

return result;

}

大功告成,测试一下,果然比之前好用多了,再让老大瞅瞅去

List hhm = Filters.filterMelons(melons, new HHMMelonPredicate());

List weight = Filters.filterMelons(melons, new WeightMelonPredicate());

第五次  一次性加了100个过滤条件


就在我沾沾自喜时候,老大又给他泼了一盆冷水。他说你以为我们的平台就买黄河蜜啊,如果前前后后有几十种瓜品种,我给你列出100种过滤条件,你怎么办?

我的心里一万个草泥马在奔腾啊???!老大是不是存心和我过不去啊!虽然经过上次改造,我的代码已经足够灵活,但是如果突然增加100个过滤条件,我仍然需要编写100个策略类来实现 每一个过滤条件。然后我们需要将策略传递给   filterMelons() 方法。

有没有不需要创建这些类的办法那?聪明的我很快发现可以使用java匿名内部类

如下所示:

List europeans = Filters.filterMelons(melons, new MelonPredicate() {

@Override

public boolean test(Melon melon) {

return “europe”.equalsIgnoreCase(melon.getOrigin());

}

});

虽然向前跨了一大步,但好像无济于事。我还是需要编写大量的代码实现此次需求。设计匿名内部类的目的,就是为了方便 Java 程序员将代码作为数据传递。有时候,匿名内部类看这比较复杂,这时候,我突然想起来老大让我学的lambda表达式,我可以用它来简化

List europeansLambda = Filters.filterMelons(

melons, m -> “europe”.equalsIgnoreCase(m.getOrigin())

);

果然看这帅多了!!!,就这样,我又一次成功完成了任务。我兴冲冲的拿着代码让老大去看看。

第六次  引入泛型


老大看着我的代码说,嗯,不错!脑袋终于开窍了。现在你考虑一下,我们的平台是做农产品的,也就是肯定不止瓜这一类水果,如果换做其他的水果,你的代码如何修改?

目前我们的MelonPredicate仅支持   Melon 类。这家伙怎么搞?说不定哪天他要买蔬菜、海参可怎么搞,总不能给他再创建好多类似MelonPredicate的接口吧。这个时候突然想起老师讲过的泛型,该它发挥作用了!

于是我定义了一个新接口Predicate

@FunctionalInterface

public interface Predicate {

boolean test(T t);

}

接下来,我们重写该   filterMelons() 方法并将其重命名为   filter()

public static  List filter(List list, Predicate predicate) {

List result = new ArrayList<>();

for (T t: list) {

if (t != null && predicate.test(t)) {

result.add(t);

}

}

return result;

}

现在,我们可以这样过滤瓜类  :

List watermelons = Filters.filter(

melons, (Melon m) -> “Watermelon”.equalsIgnoreCase(m.getType()));

同样的,我们也可以对数字做同样的事情:

List numbers = Arrays.asList(1, 13, 15, 2, 67);

List smallThan10 = Filters.filter(numbers, (Integer i) -> i < 10);

回过头来复盘一下,我们发现自从使用Java 8函数式接口和lambda表达式后,代码发生了明显的变化。

不知道细心的伙伴有没有发现我们上面的  Predicate 接口上面多了一个@FunctionalInterface 上的注解,它就是标记函数式接口的。

至此,我们通过一个需求的演变过程,了解了lambda和函数式接口的概念,同时也加深对它们的理解。其实熟悉java8的朋友都知道,在我们的 java.util.function 包下包含40多个此类接口

函数式接口lambda表达式组成了一个强大的团队。根据上面的例子,我们知道函数式接口是我们行为的高度抽象,lambda表达式我们可以看出这种行为的具体实现的一个实例。

Predicate predicate = (Melon m)-> “Watermelon”.equalsIgnoreCase(m.getType());

简而言之Lambda


lambda表达式由三部分组成,如下图所示:

以下是lambda表达式各部分的描述:

  • 在箭头的左侧,是在lambda表达式主体中使用的参数。

  • 在箭头的右侧,是lambda主体 。

  • 箭头只是lambda参数和主体的分隔符。

lambda的匿名类版本如下:

List europeans = Filters.filterMelons(melons, new Predicate() {

@Override

public boolean test(Melon melon) {

return “Watermelon”.equalsIgnoreCase(melon.getType());

}

});
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

面试难免让人焦虑不安。经历过的人都懂的。但是如果你提前预测面试官要问你的问题并想出得体的回答方式,就会容易很多。

此外,都说“面试造火箭,工作拧螺丝”,那对于准备面试的朋友,你只需懂一个字:刷!

给我刷刷刷刷,使劲儿刷刷刷刷刷!今天既是来谈面试的,那就必须得来整点面试真题,这不花了我整28天,做了份“Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法等”

image

且除了单纯的刷题,也得需准备一本【JAVA进阶核心知识手册】:JVM、JAVA集合、JAVA多线程并发、JAVA基础、Spring 原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、JAVA算法、数据结构、加密算法、分布式缓存、Hadoop、Spark、Storm、YARN、机器学习、云计算,用来查漏补缺最好不过。

image

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
你提前预测面试官要问你的问题并想出得体的回答方式,就会容易很多。

此外,都说“面试造火箭,工作拧螺丝”,那对于准备面试的朋友,你只需懂一个字:刷!

给我刷刷刷刷,使劲儿刷刷刷刷刷!今天既是来谈面试的,那就必须得来整点面试真题,这不花了我整28天,做了份“Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法等”

[外链图片转存中…(img-l5qNZLwh-1713436676194)]

且除了单纯的刷题,也得需准备一本【JAVA进阶核心知识手册】:JVM、JAVA集合、JAVA多线程并发、JAVA基础、Spring 原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、JAVA算法、数据结构、加密算法、分布式缓存、Hadoop、Spark、Storm、YARN、机器学习、云计算,用来查漏补缺最好不过。

[外链图片转存中…(img-7JzYNV8p-1713436676194)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值