一说明

这边文章主要是带大家为什么会有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. Excel导入数据库(php版)

    一.环境说明 Apache+php(PHPExcel)+HTML5+JavaScript(jQuery)+MySQL 二.前端预览 三.Excel表格 四.HTML部分 <p>按照Exce ...

  2. Python 编程语言要掌握的技能之一:使用数字与字符串的技巧

    最佳实践 1. 少写数字字面量 “数字字面量(integer literal)” 是指那些直接出现在代码里的数字.它们分布在代码里的各个角落,比如代码 del users[0] 里的 0 就是一个数字 ...

  3. 【Luogu P3375】字符串匹配KMP算法模板

    Luogu P3375 模式串:即题目中的S2所代表的意义 文本串:即题目中的S1所代表的意义 对于字符串匹配,有一种很显然的朴素算法:在S1中枚举起点一位一位匹配,失配之后起点往后移动一位,从头开始 ...

  4. JVM系列一(Java内存区域和对象创建).

    一.JVM 内存区域 堆 - Heap 线程共享,JVM中最大的一块内存,此内存的唯一目的就是存放对象实例,Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称为"GC堆"( ...

  5. Fragment源码分析

    转载请标明出处:http://blog.csdn.net/shensky711/article/details/53171248 本文出自: [HansChen的博客] 概述 Fragment表示 A ...

  6. VS Code实现markdown画流程图

    安装最新的vscode编辑器,原生支持markdown语法.不会markdow的人可以去好好学下,写文档神器!!! 1.安装Markdown Preview Enhanced插件 2.本地新建test ...

  7. Spring Cloud报错Error creating bean with name 'requestMappingHandlerMapping'

    如果我们使用Spring Cloud的Feign实现熔断,首先需要自定义一个熔断类,实现你的feign接口,然后实现方法,这些方法就是熔断方法,最后需要在你的feign接口中指定fallback为自定 ...

  8. Slickflow.Graph 开源工作流引擎快速入门之四: 图形编码建模工具使用手册

    前言: 业务人员绘制流程时,通常使用图形GUI界面交互操作来完成,然而对于需要频繁操作或者管理较多流程的系统管理用户,就需要一款辅助工具,来帮助他们快速完成流程的创建和编辑更新.Slickflow.G ...

  9. docker-primary

    docker-ce  docker网址 https://docs.docker.com/docsarchive/ Docker的安装和启动 官方安装文档链接:https://docs.docker.c ...

  10. C#程序编写高质量代码改善的157个建议【13-15】[为类型输出格式化字符串、实现浅拷贝和深拷贝、用dynamic来优化反射]

    前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html .本文主要学习记录以下内容: 建议13.为类型输出格式化字符串 建议14.正确实现浅拷贝和深 ...