一说明

这边文章主要是带大家为什么会有lamda表达式的出现,流式思想的产生。具体的Lamda表达式操作,Stream流会在后面的文章更新,有兴趣的朋友也可以加一下我微信公众号,分享学习干货。

二java8核心

  1. Lamda表达式
  2. 流和默认方法
  3. 方法引用

三引子

3.1需求

现在有批车,是中国或者英国制造的,每辆车有不同的属性,现在根据客户不同的需求挑选车。

3.2建立车的实体类

/**
* @Author lsc
* @Description <p> </p>
* @Date 2019/9/27 11:09
* @Version 1.0
*/
@Data
@AllArgsConstructor
public class Car { // 车牌号
private String code;
// 颜色
private String color;
// 生产商
private String factory;
// 价格
private double price;
}

3.3 车辆初始化

    public List<Car> InitCar(){
ArrayList<Car> carList = new ArrayList<>();
Car car1 = new Car("100", "black", "中国", 20);
Car car2 = new Car("101", "gray", "中国", 30);
Car car3 = new Car("102", "yello", "中国", 50);
Car car4 = new Car("103", "silvery", "英国", 20);
Car car5 = new Car("104", "red", "英国", 30);
carList.add(car1);
carList.add(car2);
carList.add(car3);
carList.add(car4);
carList.add(car5);
return carList;
}

3.4 客户需求实现

1 现在客户需要看看价格大于20W的车,我们以前的思想应该就是写一个方法,筛选出价格大于20W的车,对于我们so easy 对不对。

    // 通过价格获取车
public List<Car> getCarByLowPrice(List<Car> carList){
ArrayList<Car> resultList = new ArrayList<>();
for (Car car : carList){
if (car.getPrice()>20){
resultList.add(car);
}
}
return resultList;
}

测试一下

    // 获取 车价格 20 W以上的车
@Test
public void getCarByLowPriceTest(){
// 初始化车信息
List<Car> cars = carFunFactory.InitCar();
// 获取价格20W以上的车
List<Car> carByPrice1 = carFunFactory.getCarByLowPrice(cars);
System.out.println(carByPrice1);
}

输出:

[Car(code=101, color=gray, factory=中国, price=30.0), Car(code=102, color=yello, factory=中国, price=50.0), Car(code=104, color=red, factory=英国, price=30.0)]

2 现在客户需求变更想看看30W以上的车,我们就copy一下代码改个数字对把

    // 通过价格获取车
public List<Car> getCarByHightPrice(List<Car> carList){
ArrayList<Car> resultList = new ArrayList<>();
for (Car car : carList){
if (car.getPrice()>30){
resultList.add(car);
}
}
return resultList;
}

测试:

    // 获取 车价格 30 W以上的车
@Test
public void getCarByHightPriceTest(){
// 初始化车信息
List<Car> cars = carFunFactory.InitCar();
// 获取价格30W以上的车
List<Car> carByPrice1 = carFunFactory.getCarByHightPrice(cars);
System.out.println(carByPrice1);
}

3 现在有稍微一点思想的程序员就知道copy代码就因为一行不同是不是太过了,这么多重复内容,没错这时我们就知道要把价格这个参数开出来。

    // 通过价格获取车
public List<Car> getCarByPrice(List<Car> carList,double price){
ArrayList<Car> resultList = new ArrayList<>();
for (Car car : carList){
if (car.getPrice()>price){
resultList.add(car);
}
}
return resultList;
}

测试:

    // 根据价格获取车
@Test
public void getCarByPriceTest(){
// 初始化车信息
List<Car> cars = carFunFactory.InitCar();
// 获取价格30W以上的车
List<Car> carByPrice1 = carFunFactory.getCarByPrice(cars,20);
List<Car> carByPrice2 = carFunFactory.getCarByPrice(cars,30);
System.out.println(carByPrice1);
System.out.println(carByPrice2);
}

4 现在又来一位新客户它想看银色的车并且价格高于30W,还是copy一下,然后我们的思维就是再开个参数对吧。

    // 通过颜色和价格获取车
public List<Car> getCarByColarAndPrce(List<Car> carList,String color,double price){
ArrayList<Car> resultList = new ArrayList<>();
for (Car car : carList){
if (color.equals(car.getColor())){
if (car.getPrice()>30){
resultList.add(car);
}
}
}
return resultList;
}

测试:

    // 根据颜色和价格获取车
@Test
public void getCarByColorAndPriceTest(){
// 初始化车信息
List<Car> cars = carFunFactory.InitCar();
// 获取颜色为黄色,价格大于30W的车
List<Car> carByPredicate = carFunFactory.getCarByColarAndPrce(cars,"yello",30);
//[Car(code=102, color=yello, factory=中国, price=50.0)]
System.out.println(carByPredicate);
}

四 问题

如果我的车属性非常多,现在根据客户需求不断的变更,我们开的参数也会越来越多,代码里面要套很多层if判断;如果又的客户不想看一些属性的车,那么我们就不得不再copy一个方法,然后在if判定,这样的结果就会产生很多重复代码(而且就因为那几个条件不同),代码冗余,可读性很差。针对这个问题我们开始了优化之旅

五优化

1 策略模式

针对copy代码冗余和客户行为需求不断变化的问题我们可以用策略模式进行优化。

先建个接口,然后我们实现这个接口,把策略写进实现类,客户需要不同的需求,我们就调用不同的策略。

车条件判断接口:

/**
* @Author lsc
* @Description <p> </p>
* @Date 2019/9/27 14:05
* @Version 1.0
*/
public interface CarPredicate { boolean test(Car car);
}

具体实现策略一:

/**
* @Author lsc
* @Description <p>筛选红色的车 </p>
* @Date 2019/9/27 14:08
* @Version 1.0
*/
public class CarPredicateByColor implements CarPredicate {
@Override
public boolean test(Car car) {
return "red".equals(car.getColor());
}
}

具体实现策略二:

/**
* @Author lsc
* @Description <p>获取车价格大于30W的车 </p>
* @Date 2019/9/27 14:06
* @Version 1.0
*/
public class CarPredicateByPrice implements CarPredicate {
@Override
public boolean test(Car car) {
return car.getPrice()>30;
}
}

测试根据不同的策略获取车:

    @Test
public void getCarByPredicatePrice(){
// 初始化车信息
List<Car> cars = carFunFactory.InitCar();
// 获取价格大于30为银色的车
// 实现将条件代码封装进对象传递入参
List<Car> carByPredicate = carFunFactory.getCarByPredicate(cars,new CarPredicateByPrice());
// [Car(code=102, color=yello, factory=中国, price=50.0)]
System.out.println(carByPredicate);
}
@Test
public void getCarByPredicateColor(){
// 初始化车信息
List<Car> cars = carFunFactory.InitCar();
// 获取颜色为红色的车
// 实现将条件代码封装进对象传递入参
List<Car> carByPredicate = carFunFactory.getCarByPredicate(cars,new CarPredicateByColor());
// [Car(code=104, color=red, factory=英国, price=30.0)]
System.out.println(carByPredicate);
}

 策略模式已经很好的解决了copy代码冗余的问题,但随着客户需要的不断变更,我们需要很多的实现类,感觉还是有点麻烦。

2 匿名类

针对客户需求不断变化我们使用策略模式要写很多实现类的问题,可以用匿名类解决。

	@Component
public class CarFunFactory {
// 新增通过函数式接口获得车辆
public List<Car> getCarByPredicate(List<Car> carList, CarPredicate carPredicate){
ArrayList<Car> resultList = new ArrayList<>();
for (Car car : carList){
if (carPredicate.test(car)){
resultList.add(car);
}
}
return resultList;
}
} @Test
public void getCarByPredicatByAnonymous(){
// 初始化车信息
List<Car> cars = carFunFactory.InitCar();
// 获取颜色为红色的车
List<Car> carByPrice1 = carFunFactory.getCarByPredicate(cars, new CarPredicate() {
@Override
public boolean test(Car car) {
return car.getPrice()>30;
}
});
// [Car(code=102, color=yello, factory=中国, price=50.0)]
System.out.println(carByPrice1);
}

3 Lamda表达式

 从当初的copy方法到策略模式,在到匿名内部类是不是已经简化了许多代码呢?答案是肯定的,但许多程序员包括我在内都不是很喜欢匿名类,因为它不易理解,还占用很多空间资源。于是Java8引入了Lamda表达式。

    public void getCarByPredicatByLamda(){
// 初始化车信息
List<Car> cars = carFunFactory.InitCar();
// 获取颜色为红色的车
List<Car> carByPrice1 = carFunFactory.getCarByPredicate(cars,car -> car.getPrice()>30);
// [Car(code=102, color=yello, factory=中国, price=50.0)]
System.out.println(carByPrice1);
}

这边讲解一下Lamda表示语法,具体内容在后面文章发布。

示例:car -> car.getPrice()>30

解析示例格式:

car 是参数列表;

-> 是箭头

car.getPrice()>30 是方法主体

Lamda语法格式:

  • 这是我们的简写模式(方法主体为一句表达式): (参数列表)-> 方法主体
  • 非简写模式:(参数列表)-> {方法主体;}

    说明:有时候无参那么就是 () -> 方法主体

4 Stream流

 有了Lamda表达式做优化已经非常简练直观,但java8还有个思想就是流式思想,其内置很多默认方法,省去了我们自己建立判断接口。

    @Test
public void getCarByPredicatByStream(){
// 初始化车信息
List<Car> cars = carFunFactory.InitCar();
// 获取颜色为红色的车
List<Car> collect = cars.stream().filter(car -> car.getPrice() > 30).collect(Collectors.toList());
// [Car(code=102, color=yello, factory=中国, price=50.0)]
System.out.println(collect);
}

六 再看看我们平时用到Lamda的例子

1排序

    // 匿名内部类方式对车编号进行排序
@Test
public void getCarSortByAnonymous(){
// 初始化车信息
List<Car> cars = carFunFactory.InitCar();
// 获取颜色为红色的车
cars.sort(new Comparator<Car>() {
@Override
public int compare(Car o1, Car o2) {
return o1.getCode().compareTo(o2.getCode());
}
});
System.out.println(cars);
}
// 使用 lamda表达式对车编码进行排序
@Test
public void getCarSortByLamda(){
// 初始化车信息
List<Car> cars = carFunFactory.InitCar();
// 获取颜色为红色的车
cars.sort((o1, o2) -> o1.getCode().compareTo(o2.getCode()));
System.out.println(cars);
}
// 使用 Stream API 对车编号进行排序
@Test
public void getCarSortByStream(){
// 初始化车信息
List<Car> cars = carFunFactory.InitCar();
// 获取颜色为红色的车
List<Car> collect = cars.stream().sorted((o1, o2) -> o1.getCode().compareTo(o2.getCode())).collect(Collectors.toList());
System.out.println(collect);
}

2 runnable

    @Test
public void runnableTest(){
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello world youku1327");
}
});
thread.start();
}
@Test
public void runnableLamdaTest(){
Thread thread = new Thread(() -> System.out.println("hello world youku1327"));
thread.start(); }

七 总结

我们是将条件行为代码封装进了对象里面,然后将对象传递给特定的方法进行筛选出我们的需求,我们称这种操作为行为参数化

.
 之前的策略模式接口(CarPredicate)只有一个抽象方法,我们称这种接口为函数式接口,通常规范的函数式接口会带上@FunctionalInterface注解;


 java8还有个特性就是如果你的接口中没有抽象方法,但有个默认(default)方法,它也是函数式接口。


所有的匿名类实现方式我们都可以用Lamda表达式替换,Lamda表达式等于就是匿名类的简化。

八 致谢

作者坚持原创,分享干货技术,更新会有点慢;感谢观看我的文章,不足之处可以指出,如果想看更多好文章或者其他文章的源码可以关注我的微信公众号。

Java8-Lamda和Stream原理引入的更多相关文章

  1. 这可能是史上最好的 Java8 新特性 Stream 流教程

    本文翻译自 https://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/ 作者: @Winterbe 欢迎关注个人微信公众 ...

  2. Java8 如何进行stream reduce,collection操作

    Java8 如何进行stream reduce,collection操作 2014-07-16 16:42 佚名 oschina 字号:T | T 在java8 JDK包含许多聚合操作(如平均值,总和 ...

  3. Java8 方式解决Stream流转其他数组

    Java8 方式解决Stream流转其他数组 一. 题记:原来的List转数组用的是如下方式: example private static void listToStringArray(List l ...

  4. java stream 原理

    java stream 原理 需求 从"Apple" "Bug" "ABC" "Dog"中选出以A开头的名字,然后从中选 ...

  5. Java8 新特性 Stream 非短路终端操作

    非短路终端操作 Java8 新特性 Stream 练习实例 非短路终端操作,就是所有的元素都遍厉完,直到最后才结束.用来收集成自己想要的数据. 方法有: 遍厉 forEach 归约 reduce 最大 ...

  6. Java8 新特性 Stream 短路终端操作

    短路终端操作 Java8 新特性 Stream 练习实例 传入一个谓词,返回传为boolean,如果符合条件,则直接结束流. 匹配所有 allMatch 任意匹配 anymMatch 不匹配 none ...

  7. Java8 新特性 Stream 无状态中间操作

    无状态中间操作 Java8 新特性 Stream 练习实例 中间无状态操作,可以在单个对单个的数据进行处理.比如:filter(过滤)一个元素的时候,也可以判断,比如map(映射)... 过滤 fil ...

  8. Java8 新特性 Stream() API

    新特性里面为什么要加入流Steam() 集合是Java中使用最多的API,几乎每一个Java程序都会制造和处理集合.集合对于很多程序都是必须的,但是如果一个集合进行,分组,排序,筛选,过滤...这些操 ...

  9. java8学习之Stream分组与分区详解

    Stream应用: 继续举例来操练Stream,对于下面这两个集合: 需求是:将这两个集合组合起来,形成对各自人员打招呼的结果,输出的结果如: "Hi zhangsan".&quo ...

随机推荐

  1. 笔记本进入BIOS设置

    转眼间,到大三了. 在学习<Red Hat Linux 服务器搭建与管理>这门课时,刚开学第一节,就是虚拟机,但是最烦恼的是我们笔记本电脑的默认设置,它把虚拟化给禁止了. 1,首先,我们需 ...

  2. 迁移桌面程序到MS Store(12)——WPF使用UWP InkToolbar和InkCanvas

    我们在<迁移桌面程序到MS Store(4)——桌面程序调用Win10 API>提到了对Win10 API的调用,但仍存在无法在WPF中使用UWP控件的问题,虽然都是XAML控件,但却是两 ...

  3. 携程Apollo简单入门教程这一篇就够了

    1. Apollo背景 对程序配置的期望值也越来越高:配置修改后实时生效,灰度发布,分环境.分集群管理配置,完善的权限.审核机制……   废话不多说,参考官方文档   如果不想看文档, 也没关系, 跟 ...

  4. 2018092609-2 选题 Scrum立会报告+燃尽图 01

    此作业要求参见:[https://edu.cnblogs.com/campus/nenu/2019fall/homework/8683] 一.小组情况组长:迟俊文组员:宋晓丽 梁梦瑶 韩昊 刘信鹏队名 ...

  5. 协议分层(因特网5层模型)及7层OSI参考模型

    目录 因特网5层模型及7层OSI参考模型 分层的体系结构: 应用层(软件) 运输层(软件) 网络层(硬件软件混合) 链路层(硬件) 物理层(硬件) OSI模型 表示层 会话层 封装 因特网5层模型及7 ...

  6. Mac OS 终端利器 iTerm2(怕以后找不到,自存自用)

    之前一直使用 Mac OS 自带的终端,用起来虽然有些不太方便,但总体来说还是可以接受的,是有想换个终端的想法,然后今天偶然看到一个终端利器 iTerm2,发现真的很强大,也非常的好用,按照网上配置了 ...

  7. windows安装Pytorch报错:from torch._C import * ImportError: DLL load failed: 找不到指定的模块”解决方案

    问题描述 python环境下安装cpu版本pytorch,安装成功,但是导入出错. 报错如下 解决方法 参考博客,大家解决方法大概有:升级numpy.添加.dll文件到环境变量,均没有成功.本地pyt ...

  8. SpringCloud Sleuth + Zipkin 实现链路追踪

    一.Sleuth介绍   为什么要使用微服务跟踪? 它解决了什么问题? 1.微服务的现状?   随着业务的发展,单体架构变为微服务架构,并且系统规模也变得越来越大,各微服务间的调用关系也变得越来越复杂 ...

  9. linux创建文件名添加当前系统日期时间的方法

    使用`date +%y%m%d` Example: mkdir `date +%y%m%d` tar cfvz /tmp/bak.`date +%y%m%d`.tar.gz /etc YmdHM代表年 ...

  10. Scrapy 框架 (学习笔记-1)

    环境: 1.windows 10 2.Python 3.7 3.Scrapy 1.7.3 4.mysql 5.5.53 一.Scrapy 安装 1. Scrapy:是一套基于Twisted的一部处理框 ...