一说明

这边文章主要是带大家为什么会有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. 数据库05 使用percona软件来进行数据备份

    1.为什么要与用percona来备份 常见的MySQL备份工具 —跨平台性差 —备份时间长.冗余备份.浪费存储空间 mysqldump备份缺点: —效率较低.备份与还原速度慢,锁表(即备份数据库中的一 ...

  2. Elasticsearch从入门到放弃:文档CRUD要牢记

    在Elasticsearch中,文档(document)是所有可搜索数据的最小单位.它被序列化成JSON存储在Elasticsearch中.每个文档都会有一个唯一ID,这个ID你可以自己指定或者交给E ...

  3. CSV数据存取

    CSV数据的读取十分地简单 分为两部分 读 读取csv文件可以使用csv模块下的reader(f)以及DictReader(f) mport csv with open("text.csv& ...

  4. Spring与Redis整合(spring-data-redis)

    maven依赖 <properties> <!-- redis 版本 --> <redis.version>2.9.0</redis.version> ...

  5. 2019牛客暑期多校训练营(第九场) E All men are brothers

    传送门 知识点:并查集+组合数学 并查集合并操作可以理解为使得两个集合的人互相成为朋友,也就是两个集合并在了一起,答案是要求从所有人中挑出四个互相不是朋友的四个人,比较基础的组合数学知识,但因为每个集 ...

  6. python基础-网络编程part02

    TCP协议 TCP是传输控制协议,建立双向通道. 三次握手,建立连接 客户端向服务端发送建立连接的请求 服务端接收请求返回确认信息给客户端,并向客户端发送建立连接的请求 客户端接收请求返回确认信息给服 ...

  7. String类中常用的方法

    @Test public void demo(){ // 以下为String中的常用的方法及注释, 最常用的注释前有**标注 String s = "abcdefg123456"; ...

  8. Logos讲解--逆向开发

    前言 Logos是CydiaSubstruct框架中提供的一组宏定义.利于开发者使用宏进行Hook操作,其语法简单,功能是非常强大且稳定. 详细内容logos语法为http://iphonedevwi ...

  9. 使用cookies弹出层每24小时弹出一次

    第一步:下载cookies的库 https://github.com/js-cookie/js-cookie 第二步:设置Cookies的失效时间,这里有两种方法,按天计算和按小时计算 functio ...

  10. Spring Cloud Hoxton正式发布,Spring Boot 2.2 不再孤单

    距离Spring Boot 2.2.0的发布已经有一个半月左右时间,由于与之匹配的Spring Cloud版本一直没有Release,所以在这期间碰到不少读者咨询的问题都是由于Spring Boot和 ...