关于Lambda表示在工作学习中会经常用到,但并没有全面的去了解。在这里做一个较为详细的记录供以后学习查阅。主要参考Java 8 Lambda 表达式

引言


Java8之前,我们在使用Runnale创建线程的时候,经常需要将Runable实例传入new Thread中。一般采用匿名内部类将函数作为参数的形式传入

new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Before Java8,There is no Lambda expression!");
}
}).start();

之后我们可以使用Java8的新特性Lambda这样写:

new Thread( () -> System.out.println("In Java8, There is Lambda expression!") ).start();

这里相当于:

Runable runable = () -> System.out.println("In Java8, There is Lambda expression!");

可见Lambda表达式的强大之处,下面将以详细记录.


1、Java8的Lambda特性

1、Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。

2、Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

3、使用 Lambda 表达式可以使代码变的更加简洁紧凑。

2、Lambda表达式的语法

(arg1, arg2...) -> { body }
(type1 arg1, type2 arg2...) -> { body }

比如:

(int a, int b) -> {  return a + b; }
() -> System.out.println("Hello World");
(String s) -> { System.out.println(s); }

3、Lambda表达式的特征

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );

这里e的类型就是由编译器推理得到的,不需要声明类型,当然也可以声明类型,比如:

Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
Arrays.asList( "a", "b", "d" ).forEach( e -> {
System.out.print( e );
System.out.print( e );
} );
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指明表达式返回了一个数值。并且如果Lambda表达式中的语句块只有一行,则可以不用使用return语句

如下两个是一样的效果

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
int result = e1.compareTo( e2 );
return result;
} );

4、Lambda变量作用域

Lambda表达式只能引用外部被final修饰的局部变量,换句话说在Lambda表达式中我们不能修改定义在外的局部变量。

public class LambdaTest {

    public static void main(String[] args) {
//final如果不写的话,Lambda表达式会默认该变量为final
final String string="Hello "; HelloWorld test = (String message)->System.out.println(message+"World!");
test.print(string);
}
@FunctionalInterface
interface HelloWorld {
void print(String str);
default void print2() { }
}
}

5、函数式接口

(1)在学习函数式接口之前,我们先了解Java8下接口的静态方法与默认方法。

@FunctionalInterface
interface HelloWorld {
void print(String str);
//默认方法,通过实现类直接调用,不需要实现类实现该方法,提高了扩展性!
default void print2(String message) {
System.out.println(message);
}
//静态方法,直接接口调用。跟普通的static方法是一样的,不需要实现类去调用
static void print3(String message) {
System.out.println(message);
}
}
  • 默认(default)方法只能通过接口的实现类来调用,不需要实现方法,也就是说接口的实现类可以继承或者重写默认方法。

  • 静态(static)方法只能通过接口名调用,不可以通过实现类的类名或者实现类的对象调用。就跟普通的静态类方法一样,通过方法所在的类直接调用。

(2)了解了Java8的静态方法与默认方法之后,我们可以准确理解函数式接口的定义与特性:

  • 函数式接口(FunctionalImplement)是一种只含有一个抽象方法声明的接口,但是可以有多个非抽象方法的接口。类似于Java中的Marker Interface标记类型接口,比如java.io.Serializable等都是没有方法声明或属性声明的接口,主要用于通过instanceof就直接能探测一个实例是否是一个特定接口的实例。
  • 那么java.lang.Runable即是一种函数式接口,在接口中只有void run()方法。
  • 简单来说之前我们使用的匿名内部类传入参数,实则是使用匿名内部类来实例化函数式接口的对象。而之后的Lambda表达式可以更进一步简化代码

我们在看引言当中利用Runable创建线程的例子,后面写道:

Runable runable = () -> System.out.println("In Java8, There is Lambda expression!");

其实这里就是利用Lambda表达式实现实例化函数式接口的对象,比如我们自定义一个函数式接口,增加注解@FunctionalInterface,也可以不用注解,只需要符合函数式接口的要求,否则会报错!

@FunctionalInterface
interface HelloWold {
void print();
}

定义好函数式接口之后,我们可以使用Lambda Expression

public static void main(String[] args) {
//实现函数式接口的对象
HelloWold test = ()->System.out.println("HelloWorld!");
test.print();
}

如果接口不符合要求,则会报错:

6、断言(Predicate)函数式接口

Predicate函数式接口的主要作用就是提供一个test方法,接受一个参数返回一个布尔类型,PredicateStream API中进行一些判断的时候经常用到。主要用于过滤一些符合条件的逻辑,除此之外还会提供三个defalut方法与一个static方法,具体请看源代码:

@FunctionalInterface
public interface Predicate<T> { /**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t); 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);
} 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);
}
}

其中经常使用的是default方法test判断输入是否符合某个条件,下面是简单的例子。

//利用test默认方法判断x输入是否大于10
Predicate<Integer> boolValue = x -> x > 10;
System.out.println(boolValue.test(1));//false
System.out.println(boolValue.test(11));//true

Predicate断言通常跟Stream一起复合使用。

public class PredicateTest {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
PredicateTest predicateTest = new PredicateTest();
//输出大于5的数字
List<Integer> result = predicateTest.conditionFilter(list, integer -> integer > 5);
result.forEach(System.out::println);
System.out.println("-------");
//输出小于5的数字
result = predicateTest.conditionFilter(list, integer -> integer < 5);
result.forEach(System.out::println);
System.out.println("-------");
//输出所有数字
result = predicateTest.conditionFilter(list, integer -> true);
result.forEach(System.out::println);
System.out.println("-------");
}
//结合使用Stream filter/collect与Predicate
//filter过滤条件,collect将stream流转换List
public List<Integer> conditionFilter(List<Integer> list, Predicate<Integer> predicate){
return list.stream().filter(predicate).collect(Collectors.toList());
}
}

原文地址:https://blog.csdn.net/Mynewclass/article/details/80169476

最新文章

  1. [LeetCode] Shortest Word Distance II 最短单词距离之二
  2. 仿QQ消息气泡提醒
  3. Android之捕获TextView超链接
  4. B/S和C/S测试的区别
  5. Browser增加下载路径选择功能
  6. 使用Mysql ID自增长时 在Mapper的&lt;insert&gt;里添加对应的代码
  7. [原创]Postgres-XC集群笔记-概念与环境搭建
  8. jQuery插件的编写和使用 &lt;思维导图&gt;
  9. 【转】Windows环境下Android Studio v1.0安装教程
  10. 精通 Oracle+Python,第 3 部分:数据解析
  11. Ubuntu11.10与r8168网卡不兼容导致网络时断时续的问题
  12. JS 事件绑定的几种方式 小笔记
  13. select()函数详解
  14. 基于BrokerPattern服务器框架
  15. git GUI设置长期记住密码
  16. Centos 搭建named dns服务无法解析外网地址
  17. Hdoj 2018.母牛的故事 题解
  18. lamp源码安装
  19. 树莓派(RespberryPi)安装手记
  20. java系列之 原生数据类型

热门文章

  1. 【loj3045】【ZJOI2019】开关
  2. 计蒜客 39280.Travel-二分+最短路dijkstra-二分过程中保存结果,因为二分完最后的不一定是结果 (The 2019 ACM-ICPC China Shannxi Provincial Programming Contest M.) 2019ICPC西安邀请赛现场赛重现赛
  3. 洛谷P2877 [USACO07NOV]防晒霜Sunscreen
  4. Android入门教程(八)
  5. React中兄弟组件传值
  6. [总结] MSF攻击数据库服务
  7. 作业——09 安装关系型数据库MySQL 安装大数据处理框架Hadoop
  8. 第06组 Beta冲刺(4/4)
  9. 剑指offer:构建乘积数组
  10. 【spring源码分析】@Value注解原理