夯实Java基础(二十二)——Java8新特性之Lambda表达式
1、前言
Java 8于14年发布到现在已经有5年时间了,经过时间的磨练,毫无疑问,Java 8是继Java 5(发布于2004年)之后的又一个非常最重要的版本。因为Java 8里面出现了非常多新的特征,这些特征主要包含语言、编译器、库、工具和JVM等方面,具体如下:
- Lambda表达式
传送门
- 方法引用/构造器引用
传送门
- Stream API
传送门
- 新的日期处理类
传送门
- 函数式接口
传送门
- 接口中允许定义默认方法
- Optional类
传送门
- 重复注解、类型注解、通用类型推断
- 新的编译工具:jjs、jdeps
- JVM中的PermGen被Metaspace取代
- 新的Nashron引擎,允许在JVM上允许JS代码
- ……
以上最值得我们学习的应该就是Lambda表达式、Stream API和新的日期处理类。并不是说其他的就不用去学了,还是要去了解一下的,而这三个对我们来说很重要所以必须学习。
2、Lambda表达式简介
Lambda表达式本质上是一个匿名函数(方法),它没有方法名,没有权限修饰符,没有返回值声明。看起来就是一个箭头(->)从左边指向右边。我们可以把Lambda表达式理解为一段可以传递的代码(将代码像数据一样进行传递),它的核心思想是将面向对象中的传递数据变成传递行为。Lambda表达式的出现就是为了简化匿名内部类,让匿名内部类在方法中作为参数的使用更加方便(这里个人理解,可能有误!)。所以使用Lambda表达式可以让我们的代码更少,看上去更简洁,代码更加灵活。而Lambda表达式作为一种更紧凑的代码风格,使得Java的语言表达能力得到了提升。但也有它的缺点所在,如果Lambda表达式用的不好的话,调试运行和后期维护非常的麻烦。
3、Lambda表达式语法
Lambda表达式在Java语言中引入了一个新的语法元素和操作符。这个操作符为"->",该操作符被称为Lambda操作符或箭头操作符,它将Lambda分为两个部分:
- 左侧:指定了Lambda表达式所需要的所有参数。
- 右侧:指定了Lambda体,即Lambda表达式所要执行的功能。
Java8中的Lambda表达式的基本语法为:
(params) -> expression
(params) -> statement
(params) -> { statements }
上面只是基本的语法而已,所以看起来比较的简单,其中的具体使用方法有很多,如下:
①、无参数,无返回值 void。
() -> System.out.print(“Lambda…”) ;②、有一个参数,但无返回值 void
。(String s) -> System.out.print(“Lambda…”) ;
③、有参数,但是参数数据类型省略,由编译器推断,称为‘类型推断’。
(s) –> System.out.print(“Lambda…”) ;
④、若只有一个参数,方法的括号可以省略,如果多个参数则必须写上
。s–> System.out.print(“Lambda…”) ;
⑤、有参数,且有返回值,如果显式返回语句时就必须使用花括号“{}”。
(s,t) –> s+t
;或
(s,t) –> {return s+t;};
⑥、如果有两个或两个以上的参数,并且有多条语句则需要加上“{}”,一条执行语句可以省略。
(s,t) –> {
System.out.print(s) ;
System.out.print(t) ;
return s+t;
};
所以到目前为止,我们对Lambda表达式有了基本的认识,而前面讲了那么多的理论,就是为了接下来的快乐时光(写代码),用几个简单的例子来让我们好好理解一下Lambda表达式的使用:
- public class LambdaTest {
- public static void main(String[] args) {
- //1、创建线程举例
- //普通写法
- Thread thread = new Thread(new Runnable() {
- @Override
- public void run() {
- System.out.println("Ordinary Writing");
- }
- });
- thread.start();
- //Lambda写法。无参无返回void
- Thread thread1 = new Thread(() -> System.out.println("Lambda Writing"));
- thread1.start();
- //2、排序举例
- //普通写法,默认升序
- List<Integer> list = Arrays.asList(26, 65, 13, 79, 6, 123);
- Collections.sort(list,new Comparator<Integer>() {
- @Override
- public int compare(Integer o1, Integer o2) {
- return Integer.compare(o1, o2);
- }
- });
- System.out.println(list.toString());
- //Lambda表达式写法。有参有返回,“类型推断”
- Collections.sort(list,(o1,o2)-> Integer.compare(o1,o2));
- System.out.println(list.toString());
- //3、遍历list集合
- //普通写法
- list.forEach(new Consumer<Integer>() {
- @Override
- public void accept(Integer integer) {
- System.out.println(integer);
- }
- });
- //Lambda表达式写法。遍历List集合,forEach方法中的参数是Consumer<? super T> action
- //其中Consumer是Java8新的新出现的函数式接口,下面会讲到函数式接口
- list.forEach(alist-> System.out.println(alist));//只有一个参数可省略括号
- }
- }
注意:要使用Lambda表达式的前提是函数式接口,所以接下来学习一下函数式接口。
3、函数式接口
函数式接口(Functional Interface)也是Java8中的新特征。
函数式接口就是只能有一个抽象方法,同时可以有多个非抽象方法的接口(Java8中接口可以定义普通方法)。
这样接口就可以被隐式转换为Lambda表达式。
如果我们需要自定义一个函数式接口,就需要用到Java 8提供的一个特殊的注解@FunctionalInterface,该注解会检查它是否是一个函数式接口,简单的举个定义函数式接口的例子,代码如下:
- //定义函数式接口注解
- @FunctionalInterface
- public interface MyInterface {
- //抽象方法
- void method();
- //void method1();不能再定义
- //默认方法,必须用default修饰
- default void defaultMethod(){
- System.out.println("默认方法...");
- }
- //静态方法方法
- static void staticMethod(){
- System.out.println("静态方法...");
- }
- }
上面的例子可以很容易的转换成如下Lambda表达式:
- MyInterface myInterface = () -> System.out.println("MyInterface...");
我需要注意的一点是,接口中的默认方法和静态方法并不会破坏函数式接口的定义,既不会影响到Lambda表达式。同时也正因为Lambda表达式的引入,所以函数式接口也变得流行起来。
其实早在Java8之前就有很多接口是函数式接口,只是在Java8才正式提出之一特性,例如:
- java.lang.Runnable
- java.util.concurrent.Callable
- java.util.Comparator
- java.io.FileFilter
- java.awt.event.ActionListener
- ……
除了以上这些,在Java 8中还增加了一个新的包:java.util.function。它们里面包含了常用的函数式接口,该包下定义的函数式接口非常多,这里只列举比较重要的四个,如下:
(博客园的表格编辑器真的无力吐槽,实在太垃圾了,然后从其他编辑器编辑好了在截图过来!)
以下是这四个函数式接口的简单举例,理解Lambda表达式之后很容易写出来:
- public class FunctionInterfaceTest {
- public static void main(String[] args) {
- //Consumer<T> : void accept(T t);
- Consumer<Integer> consumer = (a) -> System.out.println("消费型接口..."+a);
- consumer.accept(1000);
- //Function<T, R> : R apply(T t);
- Function<String,String> function = (b) -> b;
- Object apply = function.apply("函数型接口...");
- System.out.println(apply);
- //Predicate<T> : boolean test(T t);
- Predicate predicate = (c) -> c.equals(10);
- boolean test = predicate.test(10);
- System.out.println("断定型接口..."+test);
- //Supplier<T> : T get();
- Supplier supplier=()->(int)(Math.random() * 50);
- Object o = supplier.get();
- System.out.println("供给型接口..."+o);
- }
- }
除了上面的这些基本的函数式接口,java.util.function包下还提供了一些针对多个参数的函数式接口,例如BiFunction<T,U,R>,它接收类型为T和U的对象,然后返回R对象。后面还有BiConsumer<T,U>、BiPredicate<T,U>等。同样还提供一些针对基本数据类型的特化函数式接口,例如XXXFunction:表示只接收XXX数据类型、XXXToXXXFunction:接收前一个XXX类型,然后返回后一个XXX类型、ToXXXFunction:表示返回值为XXX类型等等很多这样的类。(其中XXX只能是Int、Double和Long这三个基本数据类型)
如果有需要学习这些API的,可以自行去java.util.function包下查看学习,这里不多做描述。
4、方法引用和构造器引用
通过上面Lambda表达式的学习,如果你认为Lambda表达式已经让代码够简洁了,那么这里还有一个更加简洁的方法——方法引用。
简单来说,方法引用就是进一步的简化Lambda表达式声明的一种语法糖。也正是因为方法引用实在太简洁了,所以学习方法引用前必须要对Lambda表达式非常的熟悉,否则学习方法引用会有点吃力。
方法引用使用操作符 “::” 将对象或类的名字和方法名分隔开来。方法引用有很多种,它们的语法如下(注意后面是不要写括号的):
- 静态方法引用:ClassName::staticMethodName
- 实例上的实例方法引用:instanceName::methodName
- 类上的实例方法引用:ClassName::methodName
- 父类上的实例方法引用:super::methodName
- 构造方法引用:ClassName::new
- 数组构造方法引用:TypeName[]::new
在使用方法引用时要注意一点:引用的函数必定与定义的接口形参和返回值类型一致。
先用System.out.println()简单举例:
- //System.out.println()简单举例
- @Test
- public void test() {
- Consumer<String> consumer = (str) -> System.out.println(str);
- consumer.accept("Lambda表达式");
- PrintStream out = System.out;
- Consumer consumer1 = out::println;
- consumer1.accept("方法引用");
- }
- 其中Consumer中的accept(T t)方法中是一个参数,返回值是void,PrintStream中的println(Object x)也是一个参数,返回值也是void 。
①、静态方法引用。语法格式:ClassName::staticMethodName。
- //1、静态方法用——ClassName::staticMethodName
- @Test
- public void test1() {
- //Lambda表达式
- BiFunction<Double, Double, Double> biFunction = (x, y) -> Math.max(x, y);
- System.out.println(biFunction.apply(11.1, 22.2));
- System.out.println("-------------");
- //方法引用
- BiFunction<Double, Double, Double> biFunction1 = Math::max;
- System.out.println(biFunction1.apply(33.3, 44.4));
- //另外一组例子,其中c1与c2是一样的
- Comparator<Integer> c1 = (x, y) -> Integer.compare(x, y);
- Comparator<Integer> c2 = Integer::compare;
- }
②、实例上的实例方法引用。语法格式:instanceName::methodName。
- //2、实例上的实例方法引用——instanceName::methodName
- @Test
- public void test2(){
- Consumer<String> consumer = (str) -> System.out.println(str);
- Consumer consumer1 = System.out::println;
- Person person = new Person("唐浩荣", 20, "China");
- Supplier supplier = () -> person.getName();
- Supplier supplier1 = person::getName;
- }
③、类上的实例方法引用。语法格式:ClassName::methodName 。
- //3、类上的实例方法引用——ClassName::methodName
- public void test3(){
- BiPredicate<String, String> biPredicate = (x, y) -> x.equals(y);
- BiPredicate<String, String> biPredicate1 = String::equals;
- Function<Person, String> fun = (p) -> p.getName();
- Function<Person, String> fun2 = Person::getName;
- }
④、父类上的实例方法引用。语法格式:super::methodName。
- //4、父类上的实例方法引用——super::methodName
- @Test
- public void test4(){
- Person person=new Person();
- Supplier supplier = () -> super.toString();
- Supplier supplier1 =super::toString;
- }
⑤、构造方法引用。语法格式:ClassName::new。
- //5、构造方法引用——ClassName::new
- @Test
- public void test5() {
- Function<String, String> function = (n) -> new String(n);
- String apply = function.apply("Lambda构造方法");
- System.out.println(apply);
- Function<String, String> function1 = String::new;
- String apply1 = function.apply("构造方法引用");
- System.out.println(apply1);
- }
⑥、数组构造方法引用:TypeName[]::new。
- //6、数组构造方法引用——TypeName[]::new
- @Test
- public void test6() {
- Function<Integer, Integer[]> function = (n) -> new Integer[n];
- //Integer integer[]=new Integer[20];
- Integer[] apply = function.apply(3);
- apply[0] = 1;
- for (Integer integer : apply) {
- System.out.println(integer);
- }
- System.out.println("-----------------");
- Function<Integer, Integer[]> function1 = Integer[]::new;
- Integer[] apply1 = function1.apply(5);
- apply1[0] = 11;
- apply1[1] = 22;
- for (Integer integer : apply1) {
- System.out.println(integer);
- }
- }
夯实Java基础(二十二)——Java8新特性之Lambda表达式的更多相关文章
- 夯实Java基础系列21:Java8新特性终极指南
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...
- 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表达式基础语法,都在这儿了!!
写在前面 前面积极响应读者的需求,写了两篇Java新特性的文章.有小伙伴留言说:感觉Lambda表达式很强大啊!一行代码就能够搞定那么多功能!我想学习下Lambda表达式的语法,可以吗?我的回答是:没 ...
- java8新特性之——lambda表达式的使用
lambda表达式简介 个人理解,lambda表达式就是一种新的语法,没有什么新奇的,简化了开发者的编码,其实底层还是一些常规的代码.Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解 ...
- Java8新特性之Lambda表达式
lambda表达式是java8给我们带来的几个重量级新特性之一,借用lambda表达式,可以让我们的java程序设计更加简洁.最近新的项目摒弃了1.6的版本,全面基于java8进行开发,本文是java ...
- Java8 新特性之Lambda表达式
1. Lambda 表达式概述 Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递); Lambda 表达式可以写出更简洁,更灵活的代码 ...
- 【Java8新特性】- Lambda表达式
Java8新特性 - Lambda表达式 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! ...
- 【Java8新特性】Lambda表达式
一.Lambda 表达式 是什么? Lambda读音:拉姆达. Lambda是一个匿名函数,匿名函数就是一个没有名字的函数. Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中). ...
随机推荐
- [洛谷P4463] calc (生成函数)
首先注意到题目中 \(a\) 数组是有序的,那我们只用算有序的方案乘上 \(n!\) 即可. 而此时的答案显然 \[Ans=[x^n](1+x)(1+2x)\dots (1+Ax)=\prod_{i= ...
- qxdm,qpst,qcat抓包分析VoLTE SIP协商包
QXDM,QPST和QCAT是Qualcomm高通公司针对高通芯片的抓包分析工具. QXDM抓包分析,QPST与手机com口连接,QCAT用来分析抓包产生的isf文件(log). 使用版本: QXDM ...
- C:指针基础
内存概述 内存 内存含义: 存储器:计算机的组成中,用来存储程序和数据,辅助CPU进行运算处理的重要部分. 内存:内部存贮器,暂存程序/数据--掉电丢失 SRAM.DRAM.DDR.DDR2.DDR3 ...
- Win下PHP5.6版本安装redis扩展
首先说一下自己的环境啥的,我用的是phpstudy,其实没啥大用,就是看你的php版本啥的 1.运行phpinfo(),查看php的信息,php的位数和扩展信息,和要下载的扩展文件信息有关, 2.下载 ...
- eclipse配置class注释模板
/** * Copyright (c) ${year}, All Rights Reserved. * */ ${filecomment} ${package_declaration} ${typec ...
- 80端口被system占用
# 开始 今天配置wampserver 3.0.6的时候 发现右下角的图标一直是红色的 经验告诉我两个服务都没有运行 # 解决思路 wampserver有两个服务 一个是 Apache 服务 一个是 ...
- 吴裕雄 python 神经网络——TensorFlow 图、张量及会话
import tensorflow as tf g1 = tf.Graph() with g1.as_default(): v = tf.get_variable("v", [1] ...
- Oracle中trunc()函数用法
SQL表达式 注释 SELECT SYSDATE FROM dual --当前系统时间,24小时制 SELECT TO_CHAR(SYSDATE,'yyyy-mm-dd hh24:mi:ss') FR ...
- IIS-URL重写参数
参考:https://www.cnblogs.com/gggzly/p/5960335.html URL 重写规则由以下部分组成: 模式 - 可以理解为规则,分通配符和正则匹配 条件 - 可以 ...
- APP inventor 学习
中文教程:https://web.17coding.net/ 网页在线开发:http://app.gzjkw.net/#1 ai2.appinventor.mit.edu http://appinve ...