什么是lambda表达式?

Lambda 表达式是Java 8 的新特性,是一种新的编程语法。lambda语义简洁明了,性能良好,是Java 8 的一大亮点。废话不多说,我们来看个例子。

从内部类到lambda

lambda简化了内部类的使用,说起内部类,我第一个想到的就是创建一个线程:

Thread thread = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("hello anonymity class.");}
});

想必大家对这段代码都不陌生,在jdk1.8之前,我们可以使用内部类便捷的创建一个线程,并指定执行内容,这里打印了"hello anonymity class."。接着我们看下lambda的写法:

Thread thread = new Thread(() -> System.out.println("hello anonymity class."));

是不是简化了好多,从之前的“怎么做”到现在的“做什么”,我们不用再手动重写run方法,只需要写这个Thread要做什么事情就可以了。在Thread方法参数中,空括号 () 代表没有参数,打印语句就是要执行的方法体,而 -> 则是分割参数与方法体的符号。
我们再来看个例子,选取文件夹内的隐藏文件:

File[] hiddenFiles = new File(".").listFiles(new FileFilter() {@Overridepublic boolean accept(File pathname) {return pathname.isHidden();}
});

lambda:

File[] hiddenFiles = new File(".").listFiles(File::isHidden);

这里lambda表达式用到了类、方法和两个冒号“::”。当我们已经有了isHidden方法时,就可以用Java8 的方法引用:: 语法把方法当做参数传给listFiles()。这就叫做 函数式编程 ,即把方法(函数)当做参数来传递

这时你可能会有疑问,这lambda表达式究竟是怎么实现的呢?我们来跟一下代码。

函数式接口

Thread类有很多个构造方法,如何确定new Thread(() -> System.out.println("hello anonymity class."))这个用的是哪个构造方法?
我们可以开发工具可以轻松定位到上面所调用的Thread的构造方法,是

public Thread(Runnable target) {init(null, target, "Thread-" + nextThreadNum(), 0);
}

一个入参为Runnable的方法。为什么偏偏是这个,而不是Thread(String name)呢。这里要引入一个概念,函数式接口
函数式接口与普通接口的唯一不同点是多了@FunctionalInterface注解。标注这个接口可以用作函数式接口。Runnable就被标注为函数式接口,只有一个抽象方法:public abstract void run();入参为空,且无返回。同样的,listFiles(FileFilter filter)的参数FileFilter也是一个函数式接口,它也有一个方法:boolean accept(File pathname);入参为File对象,返回一个boolean类型

所以lambda表达式是以入参+返回值类型来匹配函数式接口的, "->"号左边为入参(多个参数用括号包裹),右边是与接口方法的返回类型相同的方法体(多行用大括号包裹)

JDK已经为我们提供了现成的函数式接口(当然我们也可以自己写),在java.util.function包下,有了这些扩展,lambda才能展现它真正的魅力。

下面我们看一些实例

  1. 对列表迭代(Consumer)
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 9, 8, 7, 6);
list.forEach(e -> System.out.print(e + " "));
//1 2 3 4 5 9 8 7 6
  1. 对列表排序(Comparator)
//打乱顺序
Collections.shuffle(list);
System.out.println(list);
//[2, 7, 5, 6, 9, 1, 8, 4, 3]
list.sort(Integer::compare);
System.out.println(list);
//[1, 2, 3, 4, 5, 6, 7, 8, 9]
  1. 过滤偶数(Predicate)
    Predicate有一个抽象方法boolean test(T t);入参为T,返回boolean。我们可以用它来做过滤操作
Predicate<Integer> p = i -> i % 2 == 0;
List<Integer> result = predicateFilter(list, p);
System.out.println(result);
//[2, 4, 6, 8]public static  <T> List<T> predicateFilter(List<T> list, Predicate<T> p) {List<T> result = new ArrayList<>();for (T t : list) {if (p.test(t)) {result.add(t);}}return result;
}
  1. 循环处理(Consumer)
    Consumer有一个抽象方法void accept(T t);入参为T,无返回。
Consumer<Integer> c = System.out::println;
consumerForEach(list, c);public static <T> void consumerForEach(List<T> list, Consumer<T> c) {for (T t : list) {c.accept(t);}
}
/*1
* 2
* 3
* 4
* 5
* 6
* 7
* 8
* 9
*/
  1. 获取商品的id(Function)
    Function有一个抽象方法R apply(T t);入参为T,返回R类型,用处更加广泛。
List<Product> productList = Arrays.asList(new Product(1L, "西红柿"),new Product(2L, "绵白糖"),new Product(3L, "黄瓜"),new Product(4L, "大蒜")
);
List<Long> productIds = productFunction(productList, Product::getId);public static <T, R> List<R> productFunction(List<T> list, Function<T, R> f) {List<R> result = new ArrayList<>();for (T t : list) {result.add(f.apply(t));}return result;
}
/*
* 4-大蒜
* 2-绵白糖
* 1-西红柿
* 3-黄瓜
*/
  1. 根据商品的权重排序(Comparator)
    即便Comparator有多个抽象方法,lambda表达式一样可以匹配的到。

匹配了int compare(T o1, T o2);方法

productList.sort((p1, p2) -> p1.getSortWeight().compareTo(p2.getSortWeight()));

Comparator还重载了compare方法,入参是一个Function<? super T, ? extends U>

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T, ? extends U> keyExtractor) {Objects.requireNonNull(keyExtractor);return (Comparator<T> & Serializable)(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));}

所以我们还可以调用这个方法来实现排序

productList.sort(Comparator.comparing(Product::getSortWeight));

Java8中常用的函数式接口

函数式接口 函数描述符
Predicate<T> T -> boolean
Consumer<T> T -> void
Function<T,R> T -> R
Supplier<T> () -> T
UnaryOperator<T> T -> T
BinaryOperator<T> (T, T) -> T
BiPredicate<L, R> (L, R) -> boolean
BiConsumer<T, U> (T, U) -> void
BiFunction<T, U, R> (T, U) -> R

lambda及函数式接口的例子

使用案例 lambda的例子 对应的接口函数
布尔表达式 (List<String> list) -> list.empty() Predicate<List<String>>
创建对象 () -> new Product(1L, “西红柿”) Supplier<Product>
消费对象 (Product p) -> System.out.println(a.getId()) Consumer<Product>
从一个对象中提取/选择 (String s) -> s.length() Function<String, Integer>
合并两个值 (int a, int b) -> a * b IntBinaryOperator
比较两个对象 (Product p1, Product p2) -> p1.getSortWeight().compareTo(p2.getSortWeight()) Comparator<Product>或 BiFunction<Product, Product, Integer>

函数式数据处理——Stream API

(stream)是Java API的新成员,它允许你以声明性方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现)。就现在来说,你可以把它们看成遍历数据集的高级迭代器。此外,流还可以透明地并行处理,你无需写任何多线程代码了!

我们来看个例子体会一下。
同样是提取商品id,现在我们不再需要调用productFunction()方法了。

List<Long> productIdList = productList.stream().map(Product::getId).collect(Collectors.toList());
  • stream()获取productIdList的流
  • map()把流中的Product映射成Long
  • collect(Collectors.toList())从流中收集内容生成新的List

中间操作和终端操作

  • 在使用流时,会有两步操作,map()对流进行操作,称之为中间操作collect()对流进行整合,称之为终端操作
    stream提供的操作方法:
    中间操作
操作 类型 返回类型 操作参数 函数描述符 作用
filter 中间 Stream<T> Predicate<T> T -> boolean 筛选
map 中间 Stream<T> function<T,R> T -> R 映射
limit 中间 Stream<T> 数量限制
sorted 中间 Stream<T> Comparator<T> (T,T) -> int 排序
distinct 中间 Stream<T> 去重
flatMap 中间 Stream<R> Function<T, R> T -> Stream<R> 平铺(展开)映射
peek 中间 Stream<T> Consumer T -> void 迭代
skip 中间 Stream<T> 跳过
builder 中间 Builder<T> Builder<T>
empty 中间 Stream<T> () -> Stream<T> 创建一个空流
of 中间 Stream<T> T -> Stream<T> 创建包含T的流
iterate 中间 Stream<T> UnaryOperator<T> (T, UnaryOperator<T>) -> Stream<T> 以一个初始值和迭代规则创建一个T流
generate 中间 Stream<T> Supplier<T> () -> Stream<T> 创建一个流
concat 中间 Stream<T> (Stream<T>, Stream<T>) -> Stream<T> 合并两个流

终端操作

操作 类型 返回类型 作用
forEach 终端 void 消费流中的每个元素并对其应用Lambda。这一操作返回void
count 终端 long 返回流中元素的个数。这一操作返回long
collect 终端 R 把流归约成一个集合,比如List、Map甚至是Integer。
toArray 终端 T[] 把流归约成一个数组
reduce 终端 T 规约函数,以一个初始值开始,按照规则计算
min 终端 Optional<T> 获取最小值
max 终端 Optional<T> 获取最大值
anyMatch 终端 boolean 流中的任意一个对象满足条件
allMatch 终端 boolean 流中的所有对象满足条件
noneMatch 终端 boolean 流中的所有对象都不满足条件
findFirst 终端 Optional<T> 返回第一个对象
findAny 终端 Optional<T> 返回任意一个对象

来一些具体的使用实例:
村头的老王最近包地赚了些钱,开了一个小超市主要经营了下面这几类商品

/*** 商品种类*/
enum GType {//水果FRUITS(1),//啤酒BEER(2),//香烟SMOKE(3),//肉类MEAT(4),//零食SNACKS(5),;GType(int goodsType) { this.goodsType = goodsType; }private int goodsType;public int getGoodsType() { return goodsType; }public void setGoodsType(int goodsType) { this.goodsType = goodsType; }
}

然后老王进了一批货

 //商品class Goods {//名称private String name;//种类private GType goodsType;//价格private Float price;//数量private Integer count;public Goods(String name, GType goodsType, Float price, Integer count) {this.name = name;this.goodsType = goodsType;this.price = price;this.count = count;}//setter and getter}//进货private static List<Goods> stock() {return Arrays.asList(new Goods("apple", GType.FRUITS, 5.0F, 30),new Goods("banana", GType.FRUITS, 3.5F, 20),new Goods("orange", GType.FRUITS, 8.0F, 40),new Goods("bread", GType.FOODS, 3.9F, 15),new Goods("milk", GType.DRINK, 6.0F, 100),new Goods("grape", GType.FRUITS, null, 10),new Goods("beer", GType.DRINK, 8.0F, 100),new Goods("cookie", GType.FOODS, 2.6F, 300),new Goods("sugar", GType.FOODS, 1.0F, 150),new Goods("moutai", GType.DRINK, 2980.0F, 1));}

接着要面对各种购物需求

    public static void main(String[] args) {List<Goods> goods = stock();System.out.println("有哪些商品?------------------");//都买哪些商品?String goodsNames = goods.stream().map(Goods::getName).collect(Collectors.joining(", "));System.out.println(goodsNames);//apple, banana, orange, bread, milk, grape, beer, cookie, sugar, moutaiSystem.out.println("有几类商品?------------------");//有几类商品?long types = goods.stream().map(Goods::getGoodsType).count();System.out.println(types);//10System.out.println("有哪些水果?------------------");System.out.println("名称-种类-价格-数量");//有哪些水果?goods.stream().filter(e -> e.getGoodsType().equals(GType.FRUITS)).forEach(System.out::println);//名称-种类-价格-数量//apple - 1 - 5.0 - 30//banana - 1 - 3.5 - 20//orange - 1 - 8.0 - 40//grape - 1 - 18.3 - 10System.out.println("最贵的商品------------------");//最贵的商品Goods dearly = goods.stream().max(Comparator.comparingDouble(Goods::getPrice)).get();System.out.println(dearly.getName());//moutaiSystem.out.println("最便宜的价格------------------");//最便宜的价格Float cheap = goods.stream().map(Goods::getPrice).sorted(Float::compare).limit(1).findAny().get();System.out.println(cheap);//1.0System.out.println("饮品按名字排序------------------");//饮品按名字排序List<Goods> sortedDrinks = goods.stream().filter(e -> e.getGoodsType().equals(GType.DRINK)).sorted(Comparator.comparing(Goods::getName)).collect(Collectors.toList());sortedDrinks.forEach(System.out::println);//beer - 3 - 8.0 - 100//milk - 3 - 6.0 - 100//moutai - 3 - 2980.0 - 1//食品库存量System.out.println("所有商品库存量------------------");int goodsCount = goods.stream().mapToInt(Goods::getCount).sum();System.out.println(goodsCount);//766//是否有免费的商品System.out.println("是否有免费的商品------------------");boolean freeGoods = goods.stream().anyMatch(e -> e.getPrice() == 0);System.out.println(freeGoods);//false//以商品种类分类System.out.println("以商品种类分类------------------");Map<GType, List<Goods>> goodsMap = goods.stream().collect(Collectors.groupingBy(Goods::getGoodsType));System.out.println(goodsMap);//{FOODS=[bread - 2 - 3.9 - 15, cookie - 2 - 2.6 - 300, sugar - 2 - 1.0 - 150], FRUITS=[apple - 1 - 5.0 - 30, banana - 1 - 3.5 - 20, orange - 1 - 8.0 - 40, grape - 1 - 18.3 - 10], DRINK=[milk - 3 - 6.0 - 100, beer - 3 - 8.0 - 100, moutai - 3 - 2980.0 - 1]}//每个商品的余量System.out.println("每个商品的余量------------------");Map<String, Integer> goodsCountMap = goods.stream().collect(Collectors.toMap(Goods::getName, Goods::getCount));System.out.println(goodsMap);//{orange=40, banana=20, apple=30, bread=15, cookie=300, milk=100, moutai=1, grape=10, sugar=150, beer=100}}

使用流时要注意一点,如果没有终端操作的话,流是不会执行的哦。

goods.stream().peek(e -> System.out.print(e.getName() + " "));
//
goods.stream().peek(e -> System.out.print(e.getName() + "-")).count();
//apple-banana-orange-bread-milk-grape-beer-cookie-sugar-moutai-

Java8新特性——lambda表达式相关推荐

  1. Java8新特性----Lambda表达式详细探讨

    Java8新特性 Lambda表达式 入门演示 案例1 如何解决 cannot be cast to java.lang.Comparable问题? 案例2 优化方式一 : 策略设计模式 优化方式二: ...

  2. java8新特性lambda表达式、函数式编程、方法引用和接口默认方法以及内部类访问外部变量

    一提到java是一种什么语言? 大多数人肯定异口同声的说是一门面向对象的语言,这种观点从我们开始学java就已经根深蒂固了,但是学到java8新特性函数式编程的时候,我才知道java并不是纯面向对象的 ...

  3. java8新特性-lambda表达式入门学习

    定义 jdk8发布新特性中,lambda是一大亮点之一.lambda表达式能够简化我们对数据的操作,减少代码量,大大提升我们的开发效率.Lambda 表达式"(lambda expressi ...

  4. java8新特性lambda表达式概述

    定义 ​ jdk8发布新特性中,lambda是一大亮点之一.lambda表达式能够简化我们对数据的操作,减少代码量,大大提升我们的开发效率.Lambda 表达式"(lambda expres ...

  5. java8新特性-lambda表达式和stream API的简单使用

    一.为什么使用lambda Lambda 是一个 匿名函数,我们可以把 Lambda表达式理解为是 一段可以传递的代码(将代码像数据一样进行传递).可以写出更简洁.更灵活的代码.作为一种更紧凑的代码风 ...

  6. java compare 返回值_关于Java你不知道的那些事之Java8新特性[Lambda表达式和函数式接口]...

    前言 为什么要用Lambda表达式? Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码,将代码像数据一样传递,这样可以写出更简洁.更灵活的代码,作为一个更紧凑的代码风 ...

  7. 2020.10.20课堂笔记(java8新特性 lambda表达式)

    一.什么是Lambda? 我们知道,对于一个Java变量,我们可以赋给其一个"值". 如果你想把"一块代码"赋给一个Java变量,应该怎么做呢? 比如,我想把右 ...

  8. Java8 新特性 -- Lambda表达式:函数式接口、方法的默认实现和静态方法、方法引用、注解、类型推测、Optional类、Stream类、调用JavaScript、Base64

    文章目录 1. Lambda表达式 1.1 Lambda表达式语法 1.2 Lambda表达式示例 1.3 说明:函数式接口 2. 方法的默认实现和静态方法 3. 方法引用 3.1 方法引用示例 4. ...

  9. Java8 新特性lambda表达式(一)初始

    本篇参考Richard Warburton的 java8 Lambdas :Functional Programming for the Masses 学习lambda表达式之前,需要知道什么是函数式 ...

最新文章

  1. oracle11g与weblogic兼容,WebLogic 10.3.6与JDK 1.7的兼容问题
  2. Pythorch使用总览
  3. c语言怎样计算栈的长度,数据结构与算法:栈 C语言实现
  4. 性能监控工具javamelody与spring的集成
  5. java 封闭实例_不能访问类型…的封闭实例
  6. 转:70个漂亮实用的JavaScript和Ajax技术(有图有例子)
  7. PHP修改表格(增删改)
  8. [转]wince中解析reg和bib文件的不同之处
  9. 博客园在我的博客添加点击小心心特效
  10. 如何在点击事件中取得复选框选中的单元格值
  11. android trace获取和分析
  12. 4月10日服务器例行维护公告,4月12日服务器例行维护公告(已完成)
  13. CocoStudio工具集开发入门之UI编辑器教程
  14. 免费网课python_Python网课推荐——免费学习Python编程
  15. 活性(Liveness)
  16. 西门子三开接线图解_接近开关三线制接线方法
  17. docker 保存 环境持久化_Docker深入浅出系列 | 容器数据持久化
  18. 360开机小助手的广告怎么关
  19. 教你一步一步实现图标无缝变形切换
  20. python远程安装软件_在家想远程公司电脑?Python + 微信一键连接!

热门文章

  1. yy神曲url解析php_歪歪神曲解析源码(参考)
  2. javascript数据类型边边角角
  3. Harbor私有镜像仓库——高可用
  4. 简单免费内网穿透教程,利用树莓派实现低成本建站 无需公网
  5. Sharding-JDBC主子表(绑定表)关联
  6. 三星苹果鏖战:苹果未衰败 研发能力决胜千里
  7. HTML和PHP输出国际象棋,PHP实现国际象棋棋盘的样式效果(代码示例)
  8. pvr查看工具 windows 下预览
  9. 读《孙悟空是个好员工》有感(2005-5-23)
  10. 【立创开源】GL823K 读卡器