lambda表达式

目的:行为参数化

Lambda表达式是简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。

Lambda的基本语法是(parameters) -> expression(parameters) -> { statements; }。其中, (parameters) -> expression 的表达式中隐含了return,如 () -> 42 (parameters) -> { statements; } 的花括号内是语句。

举例:

() -> 42   //参数为空,返回一个int
(List<String> list) -> list.isEmpty() //参数为list,返回一个boolean
(int x, int y) -> x*y //参数为两个int,返回一个int
(String s) -> System.out.println(s); //参数为一个String,不返回结果
(String s) -> {System.out.println(s);} //参数为一个String,打印字符串

哪些地方使用哪些lambda

函数式接口是只定义一个抽象方法的接口,即使拥有多个默认方法。FunctionalInterface 标注一个函数式接口,会加入编译检查。函数式接口中默认方法的目的是:改变已发布的接口而不破坏已有的实现。

在接受函数式接口为参数的地方,都可以使用lambda表达式。

栗子:

public void execute(Runnable r){
r.run();
}
execute(() -> {}); //使用lambda,Runnable是参数为空,没有返回值的函数式接口,即() -> void //fetch返回一个函数式接口,() -> String
public Callable<String> fetch() {
return () -> "Tricky example ;-)";
}

喵:为什么只有在函数式接口的地方使用呢?lambda表达式没有函数名,只有参数列表,函数主体和返回值,如果接口有多个方法,就不能直接匹配到正确的方法上了,所以,只有一个抽象方法的函数式接口可以满足。

Predicate

java.util.function.Predicate<T>是一个含有多个默认方法的函数式接口,抽象方法为:(T t) -> bool。看下代码,你就懂了~

FunctionalInterface
public interface Predicate<T> {
//接口方法,入参为泛型T,返回bool。即:(T t) -> bool
boolean test(T t);
//默认方法,and操作
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
//默认方法,取反操作
default Predicate<T> negate() {
return (t) -> !test(t);
}
//默认方法,or 操作
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
//默认方法,判断是否相等
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}

使用

Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();

Consumer

java.util.function.Consumer<T> 是一个只含有一个默认方法的函数式接口,抽象方法为:(T t) ->void。看下代码,你就懂了~

@FunctionalInterface
public interface Consumer<T> {
//接口方法,入参为泛型T,返回void。即:(T t) -> void
void accept(T t); //默认方法,可以执行级联操作
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}

Function

java.util.function.Function<T, R>是一个含有多个默认方法的函数式接口,抽象方法为:(T t) ->R。看下代码,你就懂了~

@FunctionalInterface
public interface Function<T, R> {
//接口方法,入参为泛型T,返回泛型R。即:(T t) -> R
R apply(T t);
//默认方法,实现级联操作。before方法输入V,输出T,本function输入T,输出R。
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;
}

特定方法避免装箱操作

在处理数据时,使用特定方法,可以避免装箱操作,如:IntPredicate、LongConsumer、DoubleFunction等。具体见API库。

总结

函数描述符 函数式接口
(T) ->bool java.util.function.Predicate<T>
(T) -> void java.util.function.Consumer<T>
(T) -> R java.util.function.Function<T, R>
(T,U) -> R java.util.function.BiFunction<T, U, R>
() -> T java.util.function.Supplier<T>

只要函数描述符兼容,函数式接口就可以复用。

特殊的void兼容规则:

// Predicate返回了一个boolean
Predicate<String> p = s -> list.add(s);
// Consumer返回了一个void
Consumer<String> b = s -> list.add(s);

方法引用

方法引用是调用单一方法的Lambda的快捷写法,格式ClassName::methodName。看下栗子你就懂了~

一般方法引用

(Apple a) -> a.getWeight() 等价于Apple::getWeight
() -> Thread.currentThread().dumpStack() 等价于 Thread.currentThread()::dumpStack
(str, i) -> str.substring(i) 等价于 String::substring
(String s) -> System.out.println(s) 等价于 System.out::println
(list, element) -> list.contains(element) 等价于 List::contains

主要有三类:

  • 指向静态方法的方法引用,如:Integer::parseInt
  • 指向任意类型实例方法的方法引用,如:String::length
  • 指向现有对象的实例方法的方法引用,如:User::getUserId

构造函数引用

  • 无参构造函数

    无参构造函数的函数描述符: () -> T,由上面的总结知,可以使用Supplier接口,如下:
Supplier<User> c1 = User::new;  // c1 = () -> new User();
User user = c1.get();
  • 有一个参数的构造函数

    有一个参数的构造函数的函数描述符是(T) -> R,可以使用Function接口,如下:
Function<Long, User> c2 = User::new;
User user = c2.apply(110L);
  • 有三个参数的构造函数

    有三个参数的构造函数的函数描述符是(T,U,V) -> R,没有现成的接口,需要自定义,如下:
@Data
@AllArgsConstructor
public class User {
private String name;
private Long userId;
private Integer age;
} @FunctionalInterface
public interface TriFunction<T,U,V,R> {
R create(T t, U u, V v);
} public static void main(String[] args) {
TriFunction<String, Long, Integer, User> triFunction = User::new;
User user = triFunction.create("tina", 12L, 13);
}

使用注意事项

  • Lambda表达式可以引用静态变量、成员变量和最终的(final) 或事实上最终的局部变量。

java 8 总结 之lambda的更多相关文章

  1. Java函数式编程和lambda表达式

    为什么要使用函数式编程 函数式编程更多时候是一种编程的思维方式,是种方法论.函数式与命令式编程的区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做.说白了,函数式编程是基于 ...

  2. Java核心技术-接口、lambda表达式与内部类

    本章将主要介绍: 接口技术:主要用来描述类具有什么功能,而并不给出每个功能的具体实现.一个类可以实现一个或多个接口. lambda表达式:这是一种表示可以在将来的某个时间点执行的代码块的简洁方法. 内 ...

  3. Java基础教程:Lambda表达式

    Java基础教程:Lambda表达式 本文部分内容引用自OneAPM:http://blog.oneapm.com/apm-tech/226.html 引入Lambda Java 是一流的面向对象语言 ...

  4. java函数式编程之lambda表达式

    作为比较老牌的面向对象的编程语言java,在对函数式编程的支持上一直不温不火. 认为面向对象式编程就应该纯粹的面向对象,于是经常看到这样的写法:如果你想写一个方法,那么就必须把它放到一个类里面,然后n ...

  5. 转载java 8 为什么引入 lambda

    转载:https://www.cnblogs.com/keeya/p/11404631.html 在Java8出现之前,如果你想传递一段代码到另一个方法里是很不方便的.你几乎不可能将代码块到处传递,因 ...

  6. 最全最强 Java 8 - 函数编程(lambda表达式)

    Java 8 - 函数编程(lambda表达式) 我们关心的是如何写出好代码,而不是符合函数编程风格的代码. @pdai Java 8 - 函数编程(lambda表达式) 简介 lambda表达式 分 ...

  7. Java 8:掌握 Lambda 表达式

    本文将介绍 Java 8 新增的 Lambda 表达式,包括 Lambda 表达式的常见用法以及方法引用的用法,并对 Lambda 表达式的原理进行分析,最后对 Lambda 表达式的优缺点进行一个总 ...

  8. [Java 8] (10) 使用Lambda完成函数组合,Map-Reduce以及并行化

    好文推荐!!!!! 原文见:http://blog.csdn.net/dm_vincent/article/details/40856569 Java 8中同时存在面向对象编程(OOP)和函数式编程( ...

  9. 0028 Java学习笔记-面向对象-Lambda表达式

    匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...

  10. Upgrading to Java 8——第一章 Lambda表达式

    第一章 Lambda表达式 Lamada 表达式是Java SE 8中最重要的新特性,长期以来被认为是在Java中缺失的特性,它的出现使整个java 语言变得完整.至少到目前,在这节中你将学习到什么是 ...

随机推荐

  1. Hadoop - 国内各站点最高温度、气压和风速统计

    版权说明:  本文章版权归本人及博客园共同所有,转载请标明原文出处(http://www.cnblogs.com/mikevictor07/),以下内容为个人理解,仅供参考. 一.简介 该实例统计国内 ...

  2. 利用python发送邮件

    找了很多使用python发送邮件的文章, 发现写的并不是太全, 导致坑特别多, 刚把这个坑跨过去, 在此记录下来 本代码使用163作为发送客户端, 接收邮箱随意 首先登录163邮箱, 开启POP3/S ...

  3. XRD 数据处理:使用 Origin 进行多谱图对比

    如果一个实验制备了 4 种不同条件下的样品,并分别测得了它们的 XRD 衍射谱图,那么在数据处理中如何用 Origin 软件得到一张多谱图对比的图呢? 样品间的谱图对比 如果只是谱图样品间对比(以 4 ...

  4. Unity 发布的 WebGL 使用SendMessage传递多个参数

    如果要实现Unity与浏览器的数据交互一般都会采用两种方式 方法一: Application.ExternalCall("SayHello","helloworld&qu ...

  5. 35. Search Insert Position【leetcode】

    Given a sorted array and a target value, return the index if the target is found. If not, return the ...

  6. 【HTTP权威指南】第三章-HTTP报文

    HTTP是因特网的信使,报文就是信使运送的包裹. 这一章包含: 报文如何流动 报文的三个组成部分(起始行,首部,实体的主体部分) 请求报文和响应报文的区别 请求报文支持的各种功能(方法) 响应报文返回 ...

  7. TCP和UDP的区别(Socket)

    TCP和UDP区别 TCP和UDP编程区别 TCP编程的服务器端一般步骤是:  1.创建一个socket,用函数socket():  2.设置socket属性,用函数setsockopt(); * 可 ...

  8. iOS绘图框架CoreGraphics分析

    由于CoreGraphics框架有太多的API,对于初次接触或者对该框架不是十分了解的人,在绘图时,对API的选择会感到有些迷茫,甚至会觉得iOS的图形绘制有些繁琐.因此,本文主要介绍一下iOS的绘图 ...

  9. MarkdownPad2之安装破解

    MarkdownPad2之安装破解 一.下载破解版 1.地址链接:http://pan.baidu.com/s/1i5JzG13 密码: 4jgw 2.按步骤安装后,进行汉化:[Tool]--> ...

  10. 【剑指offer】二维数组中的查找

    题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数.   注意点:要注意特殊 ...