Java8之深入理解Lambda
lambda表达式实战
从例子引出lambda
传递Runnable创建Thread
- java8之前
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
// do something
}
});
- java 8 之后
new Thread(()->{});
上边的例子比较简单,但是有两个疑问。什么是Lambda表达式?怎么使用lambda表达式?
什么是Lambda表达式?
从上述例子入手,首先我们知道Lambda一般代表的是一个匿名对象;其次我们点击“->”,IDE会帮助我们进入到符合Lambda规范的函数接口。我们来观察下这个符合规范的类的变化。
- java7 Runnable
// 省略注释
package java.lang;
public interface Runnable {
public abstract void run();
}
- java8 Runnable
// 省略注释
package java.lang;
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
我们发现java8后Runnable接口新增了一个注解@FunctionalInterface。下边我们一起来看下这个注解是什么。
FunctionalInterface
/**
* An informative annotation type used to indicate that an interface
* type declaration is intended to be a <i>functional interface</i> as
* defined by the Java Language Specification.
*
* Conceptually, a functional interface has exactly one abstract
* method. Since {@linkplain java.lang.reflect.Method#isDefault()
* default methods} have an implementation, they are not abstract. If
* an interface declares an abstract method overriding one of the
* public methods of {@code java.lang.Object}, that also does
* <em>not</em> count toward the interface's abstract method count
* since any implementation of the interface will have an
* implementation from {@code java.lang.Object} or elsewhere.
*
* <p>Note that instances of functional interfaces can be created with
* lambda expressions, method references, or constructor references.
*
* <p>If a type is annotated with this annotation type, compilers are
* required to generate an error message unless:
*
* <ul>
* <li> The type is an interface type and not an annotation type, enum, or class.
* <li> The annotated type satisfies the requirements of a functional interface.
* </ul>
*
* <p>However, the compiler will treat any interface meeting the
* definition of a functional interface as a functional interface
* regardless of whether or not a {@code FunctionalInterface}
* annotation is present on the interface declaration.
*
* @jls 4.3.2. The Class Object
* @jls 9.8 Functional Interfaces
* @jls 9.4.3 Interface Method Body
* @since 1.8
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
- 上边文档的核心意思是:@FunctionInterface注解是为了表明这个类是一个函数式接口。
- 函数式接口有这样的特点:只有一个抽象方法。java8提供了default方法,以及超类Object中的方法(toString,Equals),这些方法不计算抽象方法数量的统计中。
- 使用上:函数式接口可以配合lambda表达式、方法引用、构造引用使用。
- 如果类上标记了这个注解,编译器会在编译期进行检查
- 最后,即使我们没有标注这个注解,编译器也会将它看待成一个函数式接口
好了,从上边我们知道了lambda的特点,接下来我们来聊下怎么使用?
如何使用Lambda
首先,我们去官网查阅Java8新特性,找到Lambda表达式的说明。我们从这个文档的**“Syntax of Lambda Expressions”**部分入手,大概可以得到如下的结论。
Lambda的组成
Lambda主要由下边几部分组成;参数列表,连接符,主体。
- 参数列表
- 圆括号内部,参数以“,”分割开来。如(String a,Object b)。
- 此外,参数的类型和括号,有些时候是可以省略
- 箭头记号
- 通过“->”这种特殊符号形式,连接前后。
- 主体
- 可以由单个表达式,或者语句块组成。
- 单个表达式,如"System.out.println("xxx")"
- 语句块
- 示例1
{ System.out.println("xxx"); }
- 示例2
{ // do something return some result return 100; }
Lambda的完整用法示例
无返回值的lambda的用例
目的,将具体业务实现交给调用者处理。
- 定义一个无返回值,符合FunctionInterface规范的接口对象
interface Print<String>{
void printName(String string);
}
使用示例1
我这里的业务逻辑是根据输入参数,执行日志打印操作。实际业务场景下,可能对应的是发送邮件或者MQ这样的具体操作。
public class LambdaDemo {
public static void main(String[] args) {
PrintSomeThing(name->System.out.println(name),"Hello baigt");
}
public static void PrintSomeThing(Print<String> str,String name) {
str.printName(name);
}
}
使用示例1 的延伸使用
- 定义 一个使用类
class Doctor{
String name;
String interest;
public Doctor(String name, String interest) {
this.name = name;
this.interest = interest;
}
public void printName(Print<String> str) {
str.printName(name);
}
}
- 具体使用
Doctor doctor=new Doctor("baigt","java and javascript");
doctor.printName(name->System.out.println(name));
有返回值的lambda的用例
目的,将具体业务实现交给调用者处理,并将结果返回。
- 定义一个有返回值,符合FunctionInterface规范的接口对象
interface GetSomething<String>{
String getThing();
}
- 定义一个使用者
class Doctor{
String name;
String interest;
public Doctor(String name, String interest) {
this.name = name;
this.interest = interest;
}
public String getInterest(GetSomething<String> get) {
return get.getThing()+","+name;
}
}
- 使用示例
我这里的业务逻辑是根据输入参数(隐式interest),计算出一个结果返回出来,并对这个结果执行打印操作。
Doctor doctor=new Doctor("baigt","java and javascript");
System.out.println(doctor.getInterest(() -> "Hi"));
到此处,我们已经大概明白lambda表达式的基本用法。但是还会有两个疑问?
- 上边例子我们自定义了几个函数式接口,那么还有其他常用的函数式接口?
- 函数式接口不仅可以通过lambda表达式使用,还可以通过方法引用和构造引用来使用。那么这种引用又是怎么回事?
常用函数接口
我们选中@FunctionInterface注解类,通过Ide的Find Usages功能,会发现在java.util.function包下java8新增了很多类。这里挑几个基础的(其他的基本是功能上的增强或变种)来说。大致上有这么几种。
- Consumer
- Supplier
- Predicate
- Function
下边会做一个简单的说明和使用。可能不会细致的去讲每一个Api。旨在让大家快速熟悉使用java8 lambda。
Consumer
/**
* Represents an operation that accepts a single input argument and returns no
* result. Unlike most other functional interfaces, {@code Consumer} is expected
* to operate via side-effects.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #accept(Object)}.
*
* @param <T> the type of the input to the operation
*
* @since 1.8
*/
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
/**
* Returns a composed {@code Consumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code Consumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
首先此接口只有一个抽象方法accept,该方法接收一个入参,不返回结果。
定义使用类
public static void doConsumer(Consumer consumer,String input) {
consumer.accept(input);
}
- 使用示例1
接收 “something input”输入,并执行打印操作
Consumer consumer = input -> System.out.println(input);
doConsumer(consumer,"something input");
- 使用示例2
将两个Consumer操作串连起来,andThen的后执行。
Consumer consumer = input -> System.out.println(input);
doConsumer(consumer.andThen(input2->{
System.out.println("input2");
}),"something input");
Supplier
/**
* Represents a supplier of results.
*
* <p>There is no requirement that a new or distinct result be returned each
* time the supplier is invoked.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #get()}.
*
* @param <T> the type of results supplied by this supplier
*
* @since 1.8
*/
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
首先此接口只有一个抽象方法get,该方法不接收参数,返回一个T类型的结果。
定义使用类
public static <T> T doSupplier(Supplier<T> supplier) {
return supplier.get();
}
- 使用示例1
不传入参数,生成一个指定类型为String或Integer的对象
System.out.println(doSupplier(() -> "baigt"));
System.out.println(doSupplier(() -> {return Integer.valueOf("10");}));
Predicate
import java.util.Objects;
/**
* Represents a predicate (boolean-valued function) of one argument.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #test(Object)}.
*
* @param <T> the type of the input to the predicate
*
* @since 1.8
*/
@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);
/**
* Returns a composed predicate that represents a short-circuiting logical
* AND of this predicate and another. When evaluating the composed
* predicate, if this predicate is {@code false}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ANDed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* AND of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
}
首先此接口只有一个抽象方法test,该方法接受一个T类型的对象,返回一个boolean类型的结果。
定义使用类
public static boolean doPredicate(Predicate<String> predicate,String string) {
return predicate.test(string);
}
- 使用示例1
根据条件,判断输入对象是否符合过滤规则。
System.out.println(doPredicate(input -> input.length() > 5, "12345"));
System.out.println(doPredicate(((Predicate<String>) (input -> input.length() > 5))
.and(input -> input.equalsIgnoreCase("12345")), "12345"));
Function
import java.util.Objects;
/**
* Represents a function that accepts one argument and produces a result.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #apply(Object)}.
*
* @param <T> the type of the input to the function
* @param <R> the type of the result of the function
*
* @since 1.8
*/
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
/**
* Returns a composed function that first applies the {@code before}
* function to its input, and then applies this function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of input to the {@code before} function, and to the
* composed function
* @param before the function to apply before this function is applied
* @return a composed function that first applies the {@code before}
* function and then applies this function
* @throws NullPointerException if before is null
*
* @see #andThen(Function)
*/
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
/**
* Returns a composed function that first applies this function to
* its input, and then applies the {@code after} function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of output of the {@code after} function, and of the
* composed function
* @param after the function to apply after this function is applied
* @return a composed function that first applies this function and then
* applies the {@code after} function
* @throws NullPointerException if after is null
*
* @see #compose(Function)
*/
default <www.javachenglei.com> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
/**
* Returns a function that always returns its input argument.
*
* @param <T> the type of the input and output objects to the function
* @return a function that always returns its input argument
*/
static <T> Function<T, T> identity(www.yasenyule.com ) {
return t -> t;
}
}
首先此接口只有一个抽象方法apply,该方法接收一个T类型对象,返回一个R类型的结果。
定义使用类
public static Integer doFunction(Function<String,Integer> function,String input) {
return function.apply(input);
}
- 使用示例1
接收一个String类型的入参,返回Integer类型的结果。示例中没做具体异常判断。
System.out.println(doFunction(input -> input.length(), "baigt"));
// 上述结果为 5
System.out.println(doFunction(((Function<String, Integer> www.dayuzaixianyl.cn ) (input -> input.length())).compose(input -> String.valueOf(input.length() * 3)), "baigt"));
// 上述结果为 2
System.out.println(doFunction(((Function<String, Integer>) (input -> {
System.out.println("notcompose:"+input);
return Integer.valueOf(input)+1;
})).compose(input -> {
System.out.println("compose:"+input);
return String.valueOf(Integer.valueOf(input)*3);
}), "22"));
// 上述结果为 67
compose是先执行的部分,上述例子中,是根据输入参数进行进一步的加工,再作为输入参数传递给具体调用者。
引用
前边提到了方法引用和构造引用两种,其实构造引用是一种特殊方法引用。具体参照官方文档说明中“Kinds of Method References”部分。
种类 | 用例 |
---|---|
类名::静态方法 | String::valueOf |
实例对象::实例方法 | doctor1::getInterest |
类名::实例方法 | String::toUpperCase |
类名::new (构造引用) | String::new |
静态引用
- 使用类
public static String doStaticReference(Function<Integer,String> function, Integer input) {
return function.apply(www.zhenghongyule.com input);
}
- 示例
doStaticReference(String::valueOf,123456);
实例对象引用实例方法
- 使用类
class Doctor{
String name;
String interest;
public Doctor(String name, String interest) {
this.name = name;
this.interest =www.dajuhezc.cn interest;
}
public String getStringInstance(){
return new String(name);
}
}
- 示例
Doctor doctor1=new Doctor("baigt007","java"www.huizhonggjzc.cn);
Supplier<String> instance = doctor1::getInterest;
类引用实例方法
- 使用类
public static String doMethodReference(Function<String,String> function, String input) {
return function.apply(input);
}
- 示例
doMethodReference(String::toUpperCase,www.feishenbo.cn"baigt");O
构造引用
- 示例
Supplier<String> stringInstance = String::new;
结语
上述是个人心得,不对之处,欢迎指正。
Java8之深入理解Lambda的更多相关文章
- Java8特性详解 lambda表达式 Stream
1.lambda表达式 Java8最值得学习的特性就是Lambda表达式和Stream API,如果有python或者javascript的语言基础,对理解Lambda表达式有很大帮助,因为Java正 ...
- Java8特性详解 lambda表达式 Stream【转】
本文转自http://www.cnblogs.com/aoeiuv/p/5911692.html 1.lambda表达式 Java8最值得学习的特性就是Lambda表达式和Stream API,如果有 ...
- 夯实Java基础(二十二)——Java8新特性之Lambda表达式
1.前言 Java 8于14年发布到现在已经有5年时间了,经过时间的磨练,毫无疑问,Java 8是继Java 5(发布于2004年)之后的又一个非常最重要的版本.因为Java 8里面出现了非常多新的特 ...
- 【Java8新特性】你知道Java8为什么要引入Lambda表达式吗?
写在前面 这是一道真实的面试题,一个读者朋友出去面试,面试官竟然问他这样一个问题:你说说Java8中为什么引入Lambda表达式?引入Lambda表达式后有哪些好处呢?还好这个朋友对Java8早有准备 ...
- Java8新特性系列-Lambda
转载自:Java8新特性系列-Lambda – 微爱博客 Lambda Expressions in Java 8 Lambda 表达式是 Java 8 最流行的特性.它们将函数式编程概念引入 Jav ...
- java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合
java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合 比如,我有一张表: entity Category.java service CategoryServic ...
- Java8 新特性学习 Lambda表达式 和 Stream 用法案例
Java8 新特性学习 Lambda表达式 和 Stream 用法案例 学习参考文章: https://www.cnblogs.com/coprince/p/8692972.html 1.使用lamb ...
- 深度分析:java8的新特性lambda和stream流,看完你学会了吗?
1. lambda表达式 1.1 什么是lambda 以java为例,可以对一个java变量赋一个值,比如int a = 1,而对于一个方法,一块代码也是赋予给一个变量的,对于这块代码,或者说被赋给变 ...
- Java8 新特性之Lambda表达式
1. Lambda 表达式概述 Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递); Lambda 表达式可以写出更简洁,更灵活的代码 ...
随机推荐
- 103-PHP定义一个类
<?php class ren{ //定义人类 } class mao{ //定义猫类 } new ren(); //实例化人类 new mao(); //实例化猫类 new mao(); // ...
- 056-for循环中continue的使用
<?php ; $i <= ; $i++) { //for循环输出数值 == ) //判断变量是否为3的整数倍 { continue;//跳过本次循环剩余语句 } echo "$ ...
- 使用Linux系统,是一种什么体验?
导读 同事,从事嵌入式软件开发多年,主要开发环境用的就是linux,最疯狂的一段时间直接把系统装成linux系统,然后在linux下面虚拟一个windows操作系统,主要有些事情必须在windows才 ...
- 4 react 简书 引入 redux 的 combineReducers 对 redux 数据进行管理
1. src 下的 common 下的 header 创建 store 文件夹 下创建 reducer.js # src/common/header/store/reducer.js const st ...
- MYSQL 数据库名、表名、字段名查询
//查询所有表的所有字段: select * from information_schema.columns where table_name='sys_users' 效果: //查询指定表的所有字段 ...
- python-局域网内实现web页面用户端下载文件,easy!
好久没有发博客了,但是也没闲着,最近疫情原因一直在家远程办公,分享一下今天的干货 先说需求:某个文件压缩之后可以供用户点击下载 没想到特别好的办法,在网上搜索大多都是通过socket实现的,然后我这个 ...
- python的库有多少个?python有多少个模块?
这里列举了大概500个左右的库: ! Chardet字符编码探测器,可以自动检测文本.网页.xml的编码. colorama主要用来给文本添加各种颜色,并且非常简单易用. Prettytable主 ...
- Django——URL详解/Django中URL是如何与urls文件匹配的
URL标准语法 protocol://hostname[:port]/path/[:parameters][?query]#fragment https://i.cnblogs.com/EditPos ...
- logrotate+crond日志切割、轮询
logrotate 在工作中经常会有需求去查看日志,无论是通过应用或者系统error日志去查找问题或者通过nginx的访问日志统计站点日均PV.UV.所以体现了日志的重要性,但是通常当业务越来越大的时 ...
- Essay写作“短路”怎么办?
有些留学生在完成essay写作过程中可能会短路,写着写着不知道自己在写什么,或者是直接动不了笔了,这种情况下应该怎么办呢?下面Australiaway小编就跟同学们分享一些比较有用的方法,希望可以帮到 ...