Java8一Lambda与函数式接口
关于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方法,接受一个参数返回一个布尔类型,Predicate在Stream 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
Java8一Lambda与函数式接口的更多相关文章
- 乐字节-Java8新特性之函数式接口
上一篇小乐带大家学过 Java8新特性-Lambda表达式,那什么时候可以使用Lambda?通常Lambda表达式是用在函数式接口上使用的.从Java8开始引入了函数式接口,其说明比较简单:函数式接口 ...
- Java8内置的函数式接口
JDK 1.8 API 包含了很多内置的函数式接口.其中就包括我们在老版本中经常见到的 Comparator 和 Runnable,Java 8 为他们都添加了 @FunctionalInterfac ...
- java8学习之深入函数式接口与方法引用
函数式接口: 函数式接口[FunctionalInterface]是整个Lambda表达式的一个根源,换句话来说java8中的Lambda表达式要想彻底掌握,前提是要彻底理解好函数式接口,所以这次继续 ...
- Java8的新特性--函数式接口
目录 函数式接口 什么是函数式接口 函数式接口的使用 Java8内置的四大核心函数式接口 一.Consumer:消费型接口(void accept(T t)) 二.Supplier:供给型接口(T g ...
- lambda的函数式接口
函数式接口就是只包含一个抽象方法的接口A(不包括默认抽象方法,但包括继承来的方法):这个接口用来作为一个可变作用的方法B的参数.函数式接口的抽象方法的参数类型和返回值就是一套签名,这个签名叫做函数描述 ...
- Java8 内置的函数式接口
1.Java8 内置的四大核心函数式接口 (1)Consumer<T> : 消费型接口 void accept(T t); (2)Supplier<T> : 供 ...
- 8000字长文让你彻底了解 Java 8 的 Lambda、函数式接口、Stream 用法和原理
我是风筝,公众号「古时的风筝」.一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农! 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在 ...
- Java8新特性之函数式接口
<Java 8 实战>学习笔记系列 定义 函数式接口只定义一个抽象方法,可以有多个默认方法 函数式接口的接口名上,会被@FunctionalInterface标注 作用 函数式接口的方法可 ...
- java8学习之BiFunction函数式接口实例演示&Predicate函数式接口详解
BiFunction函数式接口: 在上次中已经对BiFunction接口进行了初步的认识,这里对它进一步学习,这里打算新建一个Person实体,然后新建若干个Person的实例存放在集合中,最后再根据 ...
随机推荐
- Cocos Creator 功能介绍
cc.Class({ extends: cc.Component, properties: { anim: cc.Animation }, playRun: function() { this.ani ...
- 什么是 Kafka Rebalance 以及关于 Rebalance Kafka-Python 社区客户端应该关注的地方
什么是 Rebalance? Rebalance 为什么会发生?Rebalance 的情况下 consumer 是否还能正确消费消息呢? 记得之前在一段时间密集面试的时候总会问候选人这些问题. 重平衡 ...
- 可持久化01trie树——模板
给你一个数,在一段区间内找到另一个数,使得他们的异或最大: trie树上存储每个数的二进制位,查询时贪心查询能让当前高位取得1的位置: 实际上是一个求前缀和的思想.每个数都开一个trie树浪费空间,当 ...
- Beta冲刺(1/5)
队名:無駄無駄 组长博客 作业博客 组员情况 张越洋 过去两天完成了哪些任务 初步任务分配 提交记录(全组共用) 接下来的计划 完善接口文档 还剩下哪些任务 学习软工的理论课 学习代码评估.测试 燃尽 ...
- mysql 存储过程 REPEAT ... UNTIL ... END REPEAT
begin declare b int; declare use_no varchar(10); declare use_name varchar(400); decla ...
- 2019SDN第7次上机作业
2019SDN第7次上机作业 1.作业要求: 作业博客链接:https://edu.cnblogs.com/campus/fzu/fzusdn2019/homework/10165 2.具体操作步骤与 ...
- vue data不可以使用箭头函数的问题解析
这篇文章主要介绍了vue data不可以使用箭头函数问题,本文通过源码解析给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下 首先需要明确,a() {}和 b: () => {} ...
- Java-JUC(十三):现在有两个线程同时操作一个整数I,做自增操作,如何实现I的线程安全性?
问题分析:正如i在多线程中如果想实现i的多线程操作,必须i要使用volitle来保证其内存可见性,但是i++自增操作不具备原子性操作,因此需要对i++这段代码确保其原子性操作即可. 方案1: 使用Re ...
- Eclipse创建Maven父子项目
Eclipse创建Maven父子项目 - 木头若愚 - CSDN博客https://blog.csdn.net/jay_1989/article/details/53906995 创建maven项目是 ...
- # 61条面向对象设计的经验原则-《OOD启思录》Arthur J.Riel
61条面向对象设计的经验原则-<OOD启思录>Arthur J.Riel 原文 http://blog.csdn.net/cpluser/article/details/129291 61 ...