Java8-1-新特性_Lambda表达式
2018-08-02 05:53:15来源:博客园 阅读 ()
最近实在是闲的蛋疼, 突然想起前一段时间使用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里面的方法引用实战.
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:Java解释执行和编译执行
下一篇:分布式锁的几种实现方式
- Spring Boot 2.3.0 新特性Redis 拓扑动态感应 2020-06-11
- 今天来介绍java 各版本的新特性,一篇文章让你了解 2020-06-10
- Spring Boot 2.3 新特性优雅停机详解 2020-06-08
- 原创 Spring Boot 2.3 新特性分层JAR 2020-06-08
- MyBatis缓存特性详解 2020-06-03
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash