Java8 新特性 -- Lambda表达式:函数式接口、方法的默认实现和静态方法、方法引用、注解、类型推测、Optional类、Stream类、调用JavaScript、Base64
文章目录
- 1. Lambda表达式
- 1.1 Lambda表达式语法
- 1.2 Lambda表达式示例
- 1.3 说明:函数式接口
- 2. 方法的默认实现和静态方法
- 3. 方法引用
- 3.1 方法引用示例
- 4. 注解(Annotation)
- 5. 类型推测
- 6. 新增Optional类
- 7. 新增Stream类
- 8. 调用JavaScript
- 9. Base64
1. Lambda表达式
Lambda
表达式是一个匿名函数(指的是没有函数名的函数),它基于数学中的λ
演算得名,直接对应于其中的Lambda
抽象。
1.1 Lambda表达式语法
Lambda
表达式允许把函数作为一个方法的参数。Lambda
表达式的基本语法如下所示:
(parameters) -> expression
// 或者
(parameters) -> { expression }
1.2 Lambda表达式示例
Arrays.asList(1, 3, 5, 7, 9).forEach(item -> System.out.println(item));
运行结果:
以上这种写法中,i
的类型由编译器推测出来的,当然,也可以显式地指定类型,如下例所示:
Arrays.asList(1, 3, 5, 7, 9).forEach((Integer item) -> System.out.println(item));
在Java8
以前,Java
语言通过匿名函数的方法来代替Lambda
表达式。
对于列表的排序,如果列表里面存放的是自定义的类,那么通常需要指定自定义的排序方法,传统的写法如下所示:
Test.java
package com.tian;import java.util.Arrays;
import java.util.Comparator;/*** @author CodeJiao*/
class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}public class Test {public static void main(String[] args) {Person[] peoples = {new Person("Jack", 20), new Person("Rose", 18)};// 自定义排序方法, 通过年龄进行排序Arrays.sort(peoples, new Comparator<Person>() {@Overridepublic int compare(Person person1, Person person2) {// 根据年龄升序排序return person1.getAge() - person2.getAge();}});for (Person people : peoples) {System.out.println(people);}}
}
运行结果:
采用Lambda
表达式后,写法如下所示:
// 自定义排序方法, 通过年龄进行排序Arrays.sort(peoples, (person1, person2) -> {// 根据年龄升序排序return person1.getAge() - person2.getAge();});
或者
// 自定义排序方法, 通过年龄进行排序Arrays.sort(peoples, (Person person1, Person person2) -> {// 根据年龄升序排序return person1.getAge() - person2.getAge();});
1.3 说明:函数式接口
Lambda
表达式是通过函数式接口(只有一个方法的普通接口)来实现的。函数式接口可以被隐式地转换为Lambda
表达式。为了与普通的接口区分开(普通接口中可能会有多个方法),JDK1.8
新增加了一种特殊的注解@FunctionalInterface
。下面给出一个函数式接口的定义:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
2. 方法的默认实现和静态方法
JDK1.8
通过使用关键字default
可以给接口中的方法添加默认实现
此外,接口中还可以定义静态方法,示例代码如下所示:
public interface Test {void method1();default void method2() {System.out.println("我是接口的默认实现方法");}static void method3() {System.out.println("我是接口中的静态方法");}
}
那么,为什么要引入接口中方法的默认实现呢?
这样做的最重要的一个目的就是为了实现接口升级。在原有的设计中,如果想要升级接口,例如给接口中添加一个新的方法,那么会导致所有实现这个接口的类都需要被修改,这给 Java
语言已有的一些框架进行升级带来了很大的麻烦。如果接口能支持默认方法的实现,那么可以给这些类库的升级带来许多便利。例如,为了支持Lambda
表达式,Collection
中引入了foreach
方法,可以通过这个语法增加默认的实现,从而降低了对这个接口进行升级的代价,不需要所有实现这个接口的类进行修改。
3. 方法引用
方法引用指的是可以直接引用Java
类或对象的方法。它可以被看成是一种更加简洁易懂的Lambda
表达式,使用方法引用后,上例中的排序代码就可以使用下面更加简洁的方式来编写:
原来:
// 自定义排序方法, 通过年龄进行排序Arrays.sort(peoples, (person1, person2) -> {// 根据年龄升序排序return person1.getAge() - person2.getAge();});
现在:
// 自定义排序方法, 通过年龄进行排序Arrays.sort(peoples, Comparator.comparing(Person::getAge));
方法引用共有下面4种形式:
- 引用构造方法:
ClassName::new
- 引用类静态方法:
ClassName::methodName
- 引用特定类的任意对象方法:
ClassName::methodName
- 引用某个对象的方法:
instanceName::methodName
3.1 方法引用示例
Test.java
package com.tian;import java.util.Arrays;
import java.util.Comparator;
import java.util.function.Supplier;/*** @author CodeJiao*/
class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public static Person getInstance(final Supplier<Person> supplier) {return supplier.get();}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public static int compareByAge(Person a, Person b) {return b.age - a.age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}class CompareProvider {public int compareByAge(Person a, Person b) {return a.getAge() - b.getAge();}
}public class Test {public static void main(String[] args) {// 引用构造方法Person p1 = Person.getInstance(Person::new);p1.setAge(22);System.out.println("测试引用构造方法:" + p1.getAge());Person[] peoples = {new Person("Jack", 20), new Person("Rose", 18)};// 引用特定类的任意对象方法Arrays.sort(peoples, Comparator.comparing(Person::getAge));System.out.println("测试引用特定类的任意对象方法:");for (Person people : peoples) {System.out.println(people);}// 引用静态方法Arrays.sort(peoples, Person::compareByAge);System.out.println("测试引用静态方法:");for (Person people : peoples) {System.out.println(people);}// 引用某个对象的方法Arrays.sort(peoples, new CompareProvider()::compareByAge);System.out.println("测试引用某个对象的方法:");for (Person people : peoples) {System.out.println(people);}}
}
运行结果:
4. 注解(Annotation)
- 1)
JDK1.5
中引入了注解机制,注解为开发人员在代码中添加信息提供了一种形式化的方法,它使得开发人员可以在某个时刻方便地使用这些数据(通过解析注解来使用这些数据)。注解的语法比较简单,除了@
符号的使用以外,它基本上与Java
语言的语法一致,Java
语言内置了三种注解方式,它们分别是@Override
(表示当前方法是覆盖父类的方法)、@Deprecated
(表示当前元素是不赞成使用的)、@SuppressWarnings
(表示关闭一些不当的编译器警告信息)。需要注意的是,它们都定义在java.lang
包中。 - 2)
JDK1.8
对注解进行了扩展。使得注解被使用的范围更广,例如可以给局部变量、泛型、方法异常等提供注解。
5. 类型推测
JDK1.8加强了类型推测机制,这种机制可以使得代码更为简洁,假如有如下类的定义。
在调用的时候,可以使用下面的代码:
在 Java 7的时候,这种写法将会产生编译错误,Java 7中的正确写法如下所示:
同理,在调用cons方法的时候的写法为:
在 Java 7
的时候需要显式地指定类型:List.cons(5,List.<Integer>nil());
6. 新增Optional类
在使用Java
语言进行编程的时候,经常需要使用大量的代码来处理空指针异常,而这种操作往往会降低程序的可读性。JDK1.8
引入了Optional
类来处理空指针的情况,从而增强了代码的可读性,下面给出一个简单的例子:
示例代码:
package com.tian;import java.util.Optional;public class Test1 {public static void main(String[] args) {Optional<String> s1 = Optional.of("Hello");// 判断是否有值if (s1.isPresent()) {System.out.println(s1.get());}Optional<String> s2 = Optional.ofNullable(null);// 判断是否有值if (s2.isPresent()) {System.out.println(s2.get());}}
}
运行结果:
7. 新增Stream类
JDK1.8
新增加了Stream
类,从而把函数式编程的风格引入到Java
语言中,Stream
的 API
提供了非常强大的功能,使用Stream
后,可以写出更加强大、更加简洁的代码(例如可以代替循环控制语句)。示例代码如下所示:
package com.tian;import java.util.*;
import java.util.stream.Collectors;class Student {private String name;private Integer age;public Student(String name, Integer age) {this.name = name;this.age = age;}public String getName() {return name;}public Integer getAge() {return age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}public class Test2 {public static void main(String[] args) {ArrayList<Student> students = new ArrayList<>();// 初始化studentsstudents.add(new Student("张有余", 10));students.add(new Student("雷磊", 13));students.add(new Student("侯家领", 10));students.add(new Student("徐曦", 15));System.out.println("找出年龄为10的第一个学生");Optional<Student> s = students.stream().filter(student ->student.getAge() == 10).findFirst();if (s.isPresent()) {System.out.println(s.toString());}System.out.println("找出年龄为10的所有学生");List<Student> listStu = students.stream().filter(student -> student.getAge() == 10).collect(Collectors.toList());listStu.forEach(stu -> {System.out.println(stu.toString());});System.out.println("对学生按照年龄分组");Map<Integer, List<Student>> map = students.stream().collect(Collectors.groupingBy(Student::getAge));Iterator<Map.Entry<Integer, List<Student>>> iterator = map.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<Integer, List<Student>> entry = iterator.next();Integer age = entry.getKey();System.out.println("age: " + age);List<Student> group = entry.getValue();for (Student student : group) {System.out.println(student.getName() + " ");}}}
}
运行结果:
此外,Stream
类还提供了parallel
、map
、reduce
等方法,这些方法用于增加对原生类并发处理的能力,有兴趣的读者可以参考Java
官方文档学习。
8. 调用JavaScript
JDK1.8
增加API
使得通过Java
程序来调用 JavaScript
代码,使用示例如下所示:
package com.tian;import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;public class Test4 {public static void main(String[] args) throws ScriptException {ScriptEngineManager manager = new ScriptEngineManager();ScriptEngine engine = manager.getEngineByName("JavaScript");// 显示引擎名称System.out.println(engine.getClass().getName());// 调用JavaScript代码System.out.println(engine.eval("function f(){return 'Hello World'};" +"f();"));}
}
运行结果:
9. Base64
Base64
编码是一种常见的字符编码,可用来作为电子邮件或 Web Service
附件的传输编码。JDK1.8
把 Base64
编码添加到了标准类库中。示例代码如下所示:
package com.tian;import java.nio.charset.StandardCharsets;
import java.util.Base64;public class Test3 {public static void main(String[] args) {String str = "Hello World";String encodeStr = Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8));System.out.println(encodeStr);String decodeSr = new String(Base64.getDecoder().decode(encodeStr));System.out.println(decodeSr);}
}
运行结果:
Java8 新特性 -- Lambda表达式:函数式接口、方法的默认实现和静态方法、方法引用、注解、类型推测、Optional类、Stream类、调用JavaScript、Base64相关推荐
- Java8新特性----Lambda表达式详细探讨
Java8新特性 Lambda表达式 入门演示 案例1 如何解决 cannot be cast to java.lang.Comparable问题? 案例2 优化方式一 : 策略设计模式 优化方式二: ...
- java8新特性lambda表达式、函数式编程、方法引用和接口默认方法以及内部类访问外部变量
一提到java是一种什么语言? 大多数人肯定异口同声的说是一门面向对象的语言,这种观点从我们开始学java就已经根深蒂固了,但是学到java8新特性函数式编程的时候,我才知道java并不是纯面向对象的 ...
- Java8新特性——lambda表达式
什么是lambda表达式? Lambda 表达式是Java 8 的新特性,是一种新的编程语法.lambda语义简洁明了,性能良好,是Java 8 的一大亮点.废话不多说,我们来看个例子. 从内部类到l ...
- java8新特性-lambda表达式入门学习
定义 jdk8发布新特性中,lambda是一大亮点之一.lambda表达式能够简化我们对数据的操作,减少代码量,大大提升我们的开发效率.Lambda 表达式"(lambda expressi ...
- java compare 返回值_关于Java你不知道的那些事之Java8新特性[Lambda表达式和函数式接口]...
前言 为什么要用Lambda表达式? Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码,将代码像数据一样传递,这样可以写出更简洁.更灵活的代码,作为一个更紧凑的代码风 ...
- java8新特性lambda表达式概述
定义 jdk8发布新特性中,lambda是一大亮点之一.lambda表达式能够简化我们对数据的操作,减少代码量,大大提升我们的开发效率.Lambda 表达式"(lambda expres ...
- 2020.10.20课堂笔记(java8新特性 lambda表达式)
一.什么是Lambda? 我们知道,对于一个Java变量,我们可以赋给其一个"值". 如果你想把"一块代码"赋给一个Java变量,应该怎么做呢? 比如,我想把右 ...
- Java8 新特性lambda表达式(一)初始
本篇参考Richard Warburton的 java8 Lambdas :Functional Programming for the Masses 学习lambda表达式之前,需要知道什么是函数式 ...
- 【Java】Java8新特性Lambda表达式和Stream API
Lambda表达式是实现支持函数式编程技术的基础. 函数式编程与面向对象编程:函数式编程将程序代码看作数学中的函数,函数本身作为另一个函数参数或返回值,即高阶函数.而面向对象编程按照真实世界客观事物的 ...
最新文章
- 一文带你读懂Python的5大特点与8大应用方向!
- LeetCode-337 House Robber III
- Groovy预览--文本处理
- 关于Java的十件事
- 技术MBA打造中国未来CTO
- 微信 小程序 python 渲染_干货 | 微信小程序自动化测试最佳实践(附 Python 源码)...
- 1. Browser 对象 - Window 对象
- android 高通替换开机logo,高通平台 开机logo 替换
- Nacos指南-服务发现:删除服务
- Activeperl安装教程
- Typecho网站访问浏览总量统计插件PageViews升级版
- 以逗号分割数组并且去除数组最后得空数据
- 【凯子哥带你学Framework】Activity启动过程全解析
- MFC入门基础(十)静态文本框()、编辑框(Edit Control)
- 常微分方程编程基础(ODE)
- mysql练习题及答案_mysql练习题及答案.doc
- ubuntu批量解压分卷文件
- JS抽象语法树AST基础学习
- 使用MBROSTool 工具制作本地硬盘多启动盘的方法总结
- Vs2017 开发 调用 WCF