Java8-1-新特性_Lambda表达式
最近实在是闲的蛋疼, 突然想起前一段时间使用Lambda表达式觉得惊为天人, 所以就去仔细的学习了一下, 整理出一份博客出来供大家观赏.
一. 什么是lambda表达式.
Lambda 是一个匿名函数,可以把 Lambda表达式 理解为是一段可以传递的代码 (将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升.
上面的概念什么意思呢?我们来看一个例子:
很久以前我们实现runnable的代码如下:
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
如果使用lambda表达式的话, 代码就会变成下面这个样子:
Runnable runnable = () -> System.out.println("Hello");
情况很明显, 使用表达式(由于lambda实在是难打, 文章后面都使用表达式代表)可以减少很多代码, 代码也会变得很简洁.但是,表达式写出的代码比较难维护, 我们只能悄咪咪的使用.为什么?因为可以装逼.
二.Lambda 表达式的基础语法
左侧 : Lambda 表达式的参数列表
右侧 : Lambda 表达式中所需执行的功能, 即 Lambda 体 语法格式一 : 无参数,无返回值
() -> System.out.println("Hello Lambda!"); 语法格式二 : 有一个参数,并且无返回值
(x) -> System.out.println(x) 语法格式三 : 若只有一个参数,小括号可以省略不写
x -> System.out.println(x) 语法格式四 : 有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
Comparator<Integer> com = (x, y) -> {
System.out.println("函数式接口");
return Integer.compare(x, y);
};
语法格式五 : 若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写
Comparator<Integer> com = (x, y) -> Integer.compare(x, y); 语法格式六 : Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”
(Integer x, Integer y) -> Integer.compare(x, y);
注 : Lambda 表达式中的参数类型都是由编译器推断得出的。 Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。 Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的 “类型推断”
三.Java8 内置的四大核心函数式接口
函数接口是只有一个抽象方法的接口,用作 Lambda 表达式的类型。
表达式这四种类型分别代表四种类型的方法, 可在后面进行方法引用.熟悉这个对之后调用带有function的方法有奇效.每种类型的接口还有兄弟姐妹, 感兴趣可以在eclipse中Ctrl+T了解一下;
可能看完这个表格不是特别理解, 我们挑一个来解释, 其他的就举一反三.
比如最常用得function, 当我们需要使用的时候可以看到, 它是需要传入两个泛型的T, R. T是参数类型, 也就是apply方法里面的参数,包括你在表达式内容里做的处理的对象类型.R是返回对象的类型.
举个例子, Function<String, Integer> flambda = s -> s.length(); s.length()是放在apply方法里用的, 因为只有一句话所以不用写return.当然也可以写成 s->{return s.length();};
四.方法引用
方法引用主要有三类。
(1) 指向静态方法的方法引用(例如 Integer 的 parseInt 方法,写作 Integer::parseInt )。
(2) 指 向 任 意 类 型 实 例 方 法 的 方 法 引 用 ( 例 如 String 的 length 方 法 , 写 作 String::length )
(3) 指向现有对象的实例方法的方法引用(假设你有一个局部变量 expensiveTransaction
用于存放 Transaction 类型的对象,它支持实例方法 getValue ,那么你就可以写 expensive-Transaction::getValue )
方法无非几种类型
1. 有参数传入(存在2个以上需要自己设计function接口), 有参数返回-->R set(T t)
2. 有参数传入,
无参数返回-->void
3. 无参数传入有参数返回-->get();
4. boolean 判断-->当然也可以用function进行转换
也就是针对不同的方法类型, 使用不同的lambda表达式;
详细的例子如下:
package cn.jdk.MethodReference; import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier; import javax.annotation.processing.SupportedOptions; import cn.jdk.lambda.Apple; /**
*
* JDK8新特性 方法引用
*
* @author 梦见猫、 2018年4月17日
*/
public class MethodReferenceTest { public static void main(String[] args) { // 1. 第一种方式, 像创建类型一样创建consumer;
Consumer<String> con = s -> System.out.println(s);
useConsumer(con, "hello world"); // 2. 第二种方式, 直接将右边的lambda表达式视为一个对象;
useConsumer(s -> System.out.println(s), "hello world"); // 3. 第三种方式, 对象引用System.out里面的方法给lambda表达式调用
// 为什么可以这样呢? 因为sysout里面的println方法符合consumer的格式, 可以使用consumer格式的表达式进行方法引用
useConsumer(System.out::println, "Hello world"); // 下面来看看其他几种类型的表达式如何进行引用
// 1.1 function 普通的function只能引用静态方法
// Function<Integer, String> funcMethodReference = String::charAt; -- Cannot
// make a static reference to the non-static method charAt(int) from the type
// String;
Function<String, Integer> funcMethodReference = Integer::parseInt;
System.out.println(funcMethodReference.apply("12345")); // 1.2 BiFunction 加强版function; --> 对象没有实例的时候成员方法的引用
// T=对象本身的类型 U=参数 R=返回类型
BiFunction<String, String, Integer> biFunctionMethodReference = String::indexOf;
// 但是呢, 这种类型的不能这样创建--The method parseInt(String) from the type Integer should be
// accessed in a static way
// BiFunction<Integer, String, Integer> biFunctionMethodReference2 =
// Integer::parseInt;
System.out.println(biFunctionMethodReference.apply("hello world", "h")); // 1.3 对象有实例的时候成员方法的引用;
// T=参数类型, R=返回值类型;
String str = "hello world";
Function<String, Integer> funcMethodReference2 = str::indexOf;
System.out.println(funcMethodReference2.apply("e")); // Supply方法省略;-->有实例entity的get方法; // 2. 初始化方法的引用;
Supplier<String> supplier = String::new;
String s = supplier.get();
System.out.println(s); // 2.1 构造函数参数为1;
Function<String, Apple> appleFuntion = Apple::new;
Apple apple = appleFuntion.apply("red");
System.out.println(apple); // 2.2 构造函数参数为2;
BiFunction<String, Long, Apple> appleFuntion1 = Apple::new;
Apple apple2 = appleFuntion1.apply("red", 100L);
System.out.println(apple2); // 2.3 如果构造函数大于2怎么办呢? 使用自定义的Function类型进行构造;
ThreeFunction<String, Long, String, ComplexApple> threeFunction = ComplexApple::new;
ComplexApple complexApple = threeFunction.apply("Green", 123L, "FuShi");
System.out.println(complexApple); //--------------------------------------------------
// 为什么说表达式可以简化代码呢? 下面我们来看一个例子
// List的Compare
List<Apple> list1 = Arrays.asList(new Apple("abc", 123), new Apple("Green", 110), new Apple("red", 124));
// 1. 最原始的方法;
Collections.sort(list1, new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
return (int) (o1.getWeight() - o2.getWeight());
}
});
System.out.println(list1); // 2. lambda表达式
List<Apple> list2 = Arrays.asList(new Apple("abc", 123), new Apple("Green", 110), new Apple("red", 124));
list2.sort((o1, o2)-> (int)o1.getWeight() - (int)o2.getWeight());
System.out.println(list2); // 3. 最强简写;
List<Apple> list3 = Arrays.asList(new Apple("a", 123), new Apple("b", 110), new Apple("red", 124));
// 可以理解为Apple::getColor就是一个function, 方法引用的几种类型都是返回function
list3.sort(Comparator.comparing(Apple::getColor));
System.out.println(list3); Function<Long, Long> funcLong = x -> x+1;
} /**
* 这个方法传入一个consumer类型的lambda表达式, 可以有三种方法进行优化
* @param consumer
* @param t
*/
private static <T> void useConsumer(Consumer<T> consumer, T t) {
consumer.accept(t);
} }
最强简写可能比较难理解, 这里我们贴源码解释一下:
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
Apple::getColor刚好作为方法引用成为一个function为c1和c2提供了值.
如果实在不能理解呢, 可以看一下https://www.jianshu.com/p/93de07fc6f03里面的方法引用实战.
Java8-1-新特性_Lambda表达式的更多相关文章
- Java8 新特性_Lambda 表达式
1. Java8新特性_简介 Lambda 表达式 函数式接口 方法引用与构造器引用 Stream API 接口中的默认方法与静态方法 新时间日期 API 减少空指针异常的容器 Optional 2. ...
- Java8新特性_lambda表达式和函数式接口最详细的介绍
Lambda表达式 在说Lambda表达式之前我们了解一下函数式编程思想,在数学中,函数就是有输入量.输出量的一套计算方案,也就是“拿什么东西做什么事情”. 相对而言,面向对象过分强调“必须通过对象的 ...
- Java8新特性-Lambda表达式是什么?
目录 前言 匿名内部类 函数式接口 和 Lambda表达式语法 实现函数式接口并使用Lambda表达式: 所以Lambda表达式是什么? 实战应用 总结 前言 Java8新特性-Lambda表达式,好 ...
- 乐字节-Java8新特性-Lambda表达式
上一篇文章我们了解了Java8新特性-接口默认方法,接下来我们聊一聊Java8新特性之Lambda表达式. Lambda表达式(也称为闭包),它允许我们将函数当成参数传递给某个方法,或者把代码本身当作 ...
- 简单了解JAVA8的新特性
JAVA8新特性会颠覆整个JAVA程序员的编程习惯 甚至如果您坚守JAVA7之前的编程习惯,今后你看比较年轻的程序员写的JAVA代码都会无法理解 所以为了保证不脱钩,我觉得有必要学习JAVA8的新特性 ...
- java8的新特性以及用法简介
1. 介绍 2 接口的默认方法 2 lambda表达式 2.1 函数式接口 2.2 方法与构造函数引用 2.3 访问局部变量 2.4 访问对象字段与静态变量 3. 内建函数式接口 3.1 Predic ...
- Java8 Stream新特性详解及实战
Java8 Stream新特性详解及实战 背景介绍 在阅读Spring Boot源代码时,发现Java 8的新特性已经被广泛使用,如果再不学习Java8的新特性并灵活应用,你可能真的要out了.为此, ...
- Java 8 新特性 - Lambda表达式
Lambda表达式 vs 匿名类既然lambda表达式即将正式取代Java代码中的匿名内部类,那么有必要对二者做一个比较分析.一个关键的不同点就是关键字 this.匿名类的 this 关键字指向匿名类 ...
- Java8常用新特性实践
前言: 时下Oracle开速迭代的Java社区以即将推出Java10,但尴尬的是不少小中企业仍使用JDK7甚至JDK6开发. 从上面列出的JDK8特性中我们可以发现Java8的部分特性很明显的是从Sc ...
- C#10新特性-lambda 表达式和方法组的改进
C# 10 中对Lambda的语法和类型进行了多项改进: 1. Lambda自然类型 Lambda 表达式现在有时具有"自然"类型. 这意味着编译器通常可以推断出 lambda 表 ...
随机推荐
- TeamViewer试用期满转免费版本方法
TeamViewer安装完企业版以后,当试用期结束,到期后,无论你卸载.重装了多少次,都无法无法成功安装个人版,从网上搜索来得到的解决办法就是:安装TeamViewer的时候与你的电脑以及网卡地址进行 ...
- c++函数集锦
1.标准C++库字符串类std::string的用法 begin 得到指向字符串开头的Iterator end 得到指向字符串结尾的Iterator rbegin ...
- spring4笔记----spring生命周期属性
init-method : 指定bean的初始化方法-spring容器会在bean的依赖关系注入完成后调用该方法 destroy-method :指定bean销毁之前的方法-spring容器将会在销毁 ...
- 获取Bing每日图片API接口
bing图片每日更新,对于这一点感觉挺不错的,如果能够把bing每日图片作为博客背景是不是很不错呢?首先我们进入Bing首页,会发现自动转到中国版.不过这没关系,中国版更符合国情,速度也比国际版快一些 ...
- firefox浏览器 插件--【维基百科+谷歌翻译】高级应用之 带图翻译
[维基词典+谷歌翻译]插件地址: https://addons.mozilla.org/zh-CN/firefox/addon/google-dictionary-and-google-t/?src= ...
- LeetCode算法题-Construct Quad Tree(Java实现)
这是悦乐书的第224次更新,第237篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第91题(顺位题号是427).我们想使用四叉树来存储N×N布尔网格.网格中的每个单元格只 ...
- puppet 横向扩展(三)
Table of Contents 1. 概述 2. 实验环境 3. 实验步骤 3.1. 机器B 的配置 3.2. 机器A 的配置 3.3. 测试配置结果 概述 横向扩展实验之三 – 将CA 认证服务 ...
- 【PS技巧】常用概念和功能操作
常用概念 1.画布大小与图像大小 画布大小是图像背景的大小,即画纸.图像大小是当前编辑的图层的所有对象大小,即画纸上的画. 常用功能操作 1.打开和新建功能 打开图片:Ctrl+O或双击工作区 图片垂 ...
- P3399 丝绸之路 dp
题目背景 张骞于公元前138年曾历尽艰险出使过西域.加强了汉朝与西域各国的友好往来.从那以后,一队队骆驼商队在这漫长的商贸大道上行进,他们越过崇山峻岭,将中国的先进技术带向中亚.西亚和欧洲,将那里的香 ...
- 设计模式のPrototypePattern(原型模式)----创建模式
一.产生的背景 这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆.当直接创建对象的代价比较大时,则采用这种模式.例如,一个对象需要在一个高代价的数据库操作之后被创建.我们可以缓存该对象,在下 ...