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 表 ...
随机推荐
- ImportError: No module named simplejson.scanner
一.出现ImportError: No module named simplejson.scanner,是没有安装simplejson,安装一下就好了. 安装指令:python setup.py in ...
- Testlink1.9.17使用方法(第十一章 其他易用性功能)
第十一章 其他易用性功能 QQ交流群:585499566 一. 自定义 一). 自定义字段管理 在主页点击[自定义字段管理]按钮-->进入自定义字段管理页面,点击[创建]按钮,可以创建一个字段, ...
- (后端)mybatis 模糊查询 mapper.xml的写法(转)
原文地址:https://blog.csdn.net/sc6231565/article/details/46412765 1. sql中字符串拼接 SELECT * FROM tableName W ...
- (python)数据结构---元组
一.描述 一个有序的元素组成的集合 元组是不可变的线性数据结构 二.元组的相关操作 1.元组元素的访问 索引不可超界,否则抛异常IndexError 支持正负索引 t = (2, 3) print(t ...
- redis sentinel集群的搭建
背景说明: 这里采用1主2从的redis集群,3个sentinel搭建高可用redis集群. 一,关于搭建redis-sentinel高可用之前,我们必须要了解redis主从搭建redis-senti ...
- IntelliJ IDEA常用快捷键(一)
Ctrl+J 键常用的组合 psvm:public static void main(String[] args) { } Serr: System.err.println("") ...
- mssql sqlserver 判断字符串大小写的方法分享
摘要:下文讲述使用sql脚本的方法判断字符串为大小写的方法分享,如下所示 实验环境:sqlserver 2008 R2 实现思路: 将字符串转换为大写或小写然后转换为二进制编码, 然后和源字符串做对比 ...
- 爬虫入门实例:利用requests库爬取笔趣小说网
w3cschool上的来练练手,爬取笔趣看小说http://www.biqukan.com/, 爬取<凡人修仙传仙界篇>的所有章节 1.利用requests访问目标网址,使用了get方法 ...
- 第十四届智能车队员培训 I/O的使用 数据方向寄存器和数据寄存器的配置 MC9S12D64处理器
I/O的使用 数据方向寄存器和数据寄存器的配置 I/O输入输出的使用: 数据方向寄存器与数据寄存器 寄存器的概念: 寄存器,是集成电路中非常重要的一种存储单元,通常由触发器组成.在集成电路设计中,寄存 ...
- 优雅的使用Spring
Bean声明的三种方式: 1.@Component, @Service, @Repository,@Controller 用于声明一个组件,程序启动时会扫描这些组件,并创建实例. 2.在applica ...