lambda是函数式编程(FP,functional program),在java8中引入,而C#很早之前就有了。在java中lambda表达式是'->',在C#中是‘=>’。

杜甫说:射人先射马,擒贼先擒王。学习一个库要学习它的入口类。lambda的入口类是Stream,一看Stream中的函数就会发现Function,Predicate等lambda元素。

一.几个概念

    函数式接口 Functional Interface,除了static和default类型的方法外,只有一个函数的接口。以前,接口中的一切方法都是public的,现在接口中可以包含default类型的实现方法了。java中没有函数指针的概念,C#中有delegate委托相当于函数指针,但java也是有办法的,用一个类,类里面有一个函数,这个类就相当于函数指针。这么整实现简单,理解简单,但是代码比较冗长。

  谓词 Predicate, 简单来说,谓词就是条件。正规来说,谓词就是一个函数boolean f(x1,x2...),表示变量x1,x2...是否满足条件f。在java中谓词的定义就是一个函数式接口。

函数(映射) Function,将一种类型的对象映射为另一种或同种类型的对象,它就是一个函数ObjectA f(ObjectB)。在java中映射的定义也是一个函数式接口。

@FunctionalInterface
public interface Function<T, R> {R apply(T t);default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {Objects.requireNonNull(before);return (V v) -> apply(before.apply(v));} default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {Objects.requireNonNull(after);return (T t) -> after.apply(apply(t));} static <T> Function<T, T> identity() {return t -> t;}
}

可见,除了apply()函数以外,其余default方法在外部都是不可见的。所以定义函数式接口的时候需要把其他函数声明称static或者default类型的。

Optional这个值表示一个对象,这个对象可能为空也可能不为空,对于它可以产生许多行为:

如果它是null,该怎么做orElse()和orElseGet()

如果不为null,该怎么做ifPresent()

判断是否为null,isPresent()

这个类看上去十分鸡肋,但用处十分广泛

package aaa;import java.util.NoSuchElementException;
import java.util.Optional;public class OptionalDemo {public static void main(String[] args) {//创建Optional实例,也可以通过方法返回值得到。Optional<String> name = Optional.of("Sanaulla");//创建没有值的Optional实例,例如值为'null'Optional<Object> empty = Optional.ofNullable(null);//isPresent方法用来检查Optional实例是否有值。if (name.isPresent()) {//调用get()返回Optional值。
          System.out.println(name.get());}try {//在Optional实例上调用get()抛出NoSuchElementException。
          System.out.println(empty.get());} catch (NoSuchElementException ex) {System.out.println(ex.getMessage());}//ifPresent方法接受lambda表达式参数。//如果Optional值不为空,lambda表达式会处理并在其上执行操作。name.ifPresent((value) -> {System.out.println("The length of the value is: " + value.length());});//如果有值orElse方法会返回Optional实例,否则返回传入的错误信息。System.out.println(empty.orElse("There is no value present!"));System.out.println(name.orElse("There is some value!"));//orElseGet与orElse类似,区别在于传入的默认值。//orElseGet接受lambda表达式生成默认值。System.out.println(empty.orElseGet(() -> "Default Value"));System.out.println(name.orElseGet(() -> "Default Value"));try {//orElseThrow与orElse方法类似,区别在于返回值。//orElseThrow抛出由传入的lambda表达式/方法生成异常。empty.orElseThrow(Exception::new);} catch (Throwable ex) {System.out.println(ex.getMessage());}//map方法通过传入的lambda表达式修改Optonal实例默认值。 //lambda表达式返回值会包装为Optional实例。Optional<String> upperName = name.map((value) -> value.toUpperCase());System.out.println(upperName.orElse("No value found"));//flatMap与map(Funtion)非常相似,区别在于lambda表达式的返回值。//map方法的lambda表达式返回值可以是任何类型,但是返回值会包装成Optional实例。//但是flatMap方法的lambda返回值总是Optional类型。upperName = name.flatMap((value) -> Optional.of(value.toUpperCase()));System.out.println(upperName.orElse("No value found"));//filter方法检查Optiona值是否满足给定条件。//如果满足返回Optional实例值,否则返回空Optional。Optional<String> longName = name.filter((value) -> value.length() > 6);System.out.println(longName.orElse("The name is less than 6 characters"));//另一个示例,Optional值不满足给定条件。Optional<String> anotherName = Optional.of("Sana");Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);System.out.println(shortName.orElse("The name is less than 6 characters"));}}

View Code

二.lambda表达式

有两个作用

* 作为函数指针

* 替代匿名内部类,替代函数式接口(FunctionalInterface)

lambda不是语法糖,它在内部实现上也跟匿名内部类不同,匿名内部类需要进行类文件加载,而lambda表达式不用,所以lambda表达式效率比匿名内部类高。

三种用法

用'(x1,x2,x3)'表示传入参数

如果无参写作’()‘

参数类型可以指明,也可以不指明,java会根据后半部分函数形参自动推断出来。

        List<String> a = Arrays.asList("we i di ao is great".split(" "));a.forEach((s) -> System.out.println(s));// 表达式a.forEach((String s) -> {System.out.println(s);});// 语句块a.forEach(System.out::println);// 函数

方法引用

object::fun()

className::fun()静态方法引用

className::new  构造函数引用

public class LambdaIntro {// functional interface 函数式接口public static interface ItemWithIndexVisitor<E> {public void visit(E item, int index);}public static <E> void eachWithIndex(List<E> list,ItemWithIndexVisitor<E> visitor) {for (int i = 0; i < list.size(); i++) {visitor.visit(list.get(i), i);}}// 一个普通函数,用作函数指针public static <E> void printItem(E value, int index) {String output = String.format("%d -> %s", index, value.toString());System.out.println(output);}public static void main(String[] args) {List<String> list = Arrays.asList("A", "B", "C");// 第一种方式eachWithIndex(list, (value, index) -> {String output = String.format("%d -> %s", index, value);System.out.println(output);});// 第二种方式
        eachWithIndex(list, LambdaIntro::printItem);}
}

三.使用Stream

创建Stream的两种方式

* Stream接口的工厂方法

* 集合框架的stream()函数

首先来了解使用Stream接口来创建Stream,可以创建三种流:普通枚举流,产生器,迭代器。

        //of:通过枚举方式创建流Stream<Integer> one = Stream.of(1, 2, 3);//流是可以拼接的,从而产生新流Stream<Integer> two = Stream.concat(one, Stream.of(4, 5, 6));two.forEach(System.out::println);//逐个加入,那就用Builder构建器来实现Builder<Integer> builder = Stream.builder();Stream<Integer> three = builder.add(3).add(4).build();three.forEach((s) -> System.out.println(s));//产生器流generatorRandom random = new Random();Stream<Integer> four = Stream.generate(() -> random.nextInt());four.limit(10).forEach(System.out::println);//迭代器iterator,UnaryOperator一元运算符可以通过lambda表达式来创建Stream<Integer>five=Stream.iterate(2, new UnaryOperator<Integer>() {@Overridepublic Integer apply(Integer t) {return t = (t * 5 + 7) % 13;}});five.limit(10).forEach(System.out::println);

注意产生器generator和迭代器iterator是无限输出的,可以用limit来约束之。

集合框架都继承了Collection接口,而Collection接口就有一个stream()函数。所以剩下的任务就是如何利用流的强大特性来写出优雅的代码来。

要想深刻的了解Stream的一些函数,那就先不要使用lambda表达式,一旦了解它的普通实现,很容易改写成lambda的形式。

流Stream中的函数明显分为两类,一类返回值还是Stream,可以继续用流来处理,另一类返回值不是Stream,不能再用流中函数处理了。

Stream filter(Predicate)删除掉流中不满足条件的元素并返回新的Stream

Stream map(Function)映射,把流中的元素映射一下变成一个新流,还有mapToInt(),mapToLong(),mapToDouble()等函数,它们终究还是映射,只是映射结果更单一。map是一对一映射,flatMap是一对多映射。把一个元素映射成多个元素

        Arrays.asList(1, 2, 3).stream().flatMap(new Function<Integer, Stream<Integer>>() {@Overridepublic Stream<Integer> apply(Integer t) {return Arrays.asList(t, t + 10, t + 100).stream();}}).forEach(System.out::println);

输出为1 11 101 2 12 102 3 13 103   中间我省略了换行符

distinct()去除流中重复元素

sorted()和sorted(Comparator cmp)对流中元素排序

peek()弹出一个元素

        Stream.of("one", "two", "three", "four").filter(e -> e.length() > 3).peek(e -> System.out.println("Filtered value: " + e)).map(String::toUpperCase).peek(e -> System.out.println("Mapped value: " + e)).collect(Collectors.toList());

执行结果

Filtered value: three
Mapped value: THREE
Filtered value: four
Mapped value: FOUR

limit(int cnt)只返回cnt个元素,skip(int cnt)跳过cnt个元素。

forEach(Consumer consumer)对于每一个元素都执行某种操作

reduce()将多个值映射为一个值,实现多对一映射

         Stream.of("one", "two", "three", "four").reduce(new BinaryOperator<String>() {@Overridepublic String apply(String t, String u) {System.out.println(t+":"+u);return t + "," + u;}}).ifPresent(System.out::println);

输出为

one:two
one,two:three
one,two,three:four
one,two,three,four

可见,apply(t,u)函数中的t表示当前总量,u表示当前元素。

reduce(T identity,BinaryOperator<T>f)表示带初始值的reduce,比如求和函数,如果identity=9,表示一开始sum=9,此函数返回具体的对象。

        String s = Stream.of("one", "two", "three", "four").reduce("baga",new BinaryOperator<String>() {@Overridepublic String apply(String t, String u) {return t +","+ u;}});System.out.println(s);

输出:

baga,one,two,three,four

collect()

Map<String, Map<String, List<Person>>> peopleByStateAndCity= personStream.collect(Collectors.groupingBy(Person::getState,Collectors.groupingBy(Person::getCity)));

        String s=Stream.of("one", "two", "three", "four").collect(Collectors.joining(","));System.out.println(s);

输出one,two,three,four

Collectors包含许多有用的静态方法

聚集函数min(),max(),count()很像sql中的聚集函数

匹配函数allMatch(Predicate p),anyMatch(Predicate p),noneMath(Predicate p)流中全部匹配,部分匹配,完全不匹配,返回布尔值

转载于:https://www.cnblogs.com/weiyinfu/p/5468967.html

java lambda表达式学习笔记相关推荐

  1. [研究笔记]Lambda表达式学习笔记

    最近正好用到,就稍微做一下学习笔记.全部经过自己理解的归纳总结,坚持更新. Lambda表达式强大到和图灵机等价,而且极其简洁.优美,太好玩了! ==== Formal Defination Lamb ...

  2. mybatis-plus lambda表达式学习笔记

    使用mybatis-plus的好处在于可以通过Java代码实现Sql逻辑,不需要像mybatis需要通过xml编写Sql语句操作数据库,实现了零配置和手写Sql的烦恼. mybatis-plus中的l ...

  3. Java三元表达式学习笔记

    活不多说,直接上代码 ----------------------------------------以下代码仅为个人学习理解,简单明了,仅供参考--------------------------- ...

  4. Java Lambda 表达式(又名闭包 (Closure)/ 匿名函数 ) 笔记

    Java Lambda 表达式(又名闭包 (Closure)/ 匿名函数 ) 笔记 根据 JSR 335, Java 终于在 Java 8 中引入了 Lambda 表达式.也称之为闭包或者匿名函数. ...

  5. Java快速入门学习笔记3 | Java语言中的表达式与操作符

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  6. Java Lambda 表达式快速学习

    Lambda 表达式来源于数学, 因为其简洁性,很多开发语言都支持, Java 在版本8 开始引入. Lamba 表达式是什么? 匿名内部类 接口只能有一个需要被实现的方法 Lamba 表达式作用 代 ...

  7. Java 8 实战学习笔记

    Java 8 实战学习笔记 @(JAVASE)[java8, 实战, lambda] 文章目录 Java 8 实战学习笔记 参考内容 Lambda表达式 Lambda环绕执行模式(抽离步骤) 原始代码 ...

  8. 深入理解Java Lambda表达式,匿名函数,闭包

    前言 对于Lambda表达式一直是知其然不知其所以然,为了搞清楚什么是Lambda表达式,以及Lambda表达式的用法和作用,本文应运而生当做学习笔记分享出来,欢迎指正交流. 什么是Lambda 让我 ...

  9. Java Lambda表达式入门

    本文转自:http://blog.csdn.net/renfufei... 转载请注明出处 原文链接: Start Using Java Lambda Expressions 下载示例程序 Examp ...

最新文章

  1. Python 连接Sql Server数据库 MSSql
  2. tensorflow 代码调试工具tfdbg的用法
  3. 用url传值,如何传多个值
  4. 移动端布局的几种方式
  5. 寄娱于学第2天——PHP骰子游戏篇--优化
  6. 如何用架构师思维解读区块链技术?
  7. fixed与sticky的区别
  8. 海洋影音盒 V 2.0
  9. 整合Spring Cloud微服务分布式云架构技术点
  10. ShuffleNet在Caffe框架下的实现
  11. 写出Oracle分页语句,Oracle分页语句
  12. ffmpeg使用心得
  13. SAP ABAP ZBA_R004 批量导入角色里的事务代码,解放BASIS的双手
  14. React Hooks 分享
  15. 51单片机实战教程(34 线缆摇摆测试机设计)
  16. 移动端Vin码识别技术发展应用
  17. android扫码支付宝ofo,六大共享单车接入支付宝 ofo 等免押金扫一扫可骑走
  18. Ground Truth是什么意思
  19. 百度地图标注不能清除问题(点聚合)
  20. 汇编:CPU结构 - FLAG标志寄存器和相关指令

热门文章

  1. selenium定位方式
  2. PlaceholderImageView
  3. 2016022604 - redis命令介绍
  4. HDU4628+状态压缩DP
  5. MOSS工作流任务权限控制
  6. 【Java从0到架构师】Linux 应用 - 软件包管理、软件安装
  7. 【重识 HTML + CSS】列表、表格、表单
  8. 【Python笔记】字典
  9. 信息系统项目管理06——项目进度管理
  10. IntelliJIDEA和tomcat在浏览器js乱码问题解决