java8新特性简介
- 速度更快,修改了一些底层的数据结构和内存模型。比如说HashMap。在JDK7之前,采用的是数组+链表的数据结构,到jdk8之后改为数组+链表+红黑树,这是数据结构的修改。再比如说,取消永久代,改为元空间,这是内存模型的更改
- 代码更少,增加了lambda表达式
- 强大的Stream API
- 便于并行
- 最大化减少空指针异常
lambda表达式
1、为什么要使用lambda表达式
Lambda是一个匿名函数,我们可以把Lambda表达式理解为一段可以传递的代码(将代码像数据一样传递)。可以写出更简洁更灵活的代码。作为一种紧凑的代码风格,使java的语言表达能力得到了提升
2、入门小案例
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>java8</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
</dependencies>
</project>
- TestLambda.java类
package com.xuzhi.lambda;
import com.xuzhi.entity.Employee;
import com.xuzhi.predicate.FilterEmployeeByAge;
import com.xuzhi.predicate.FilterEmployeeBySalary;
import com.xuzhi.predicate.MyPredicate;
import org.junit.Test;
import java.util.*;
/**
* Author: 徐志
* Date: 2020/8/1 9:58
*/
public class TestLambda {
/**
* 使用匿名内部类来实现
*/
@Test
public void test1() {
Comparator<Integer> com = new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
TreeSet<Integer> ts=new TreeSet<Integer>(com);
}
/**
* 使用Lambda表达式来实现
*/
@Test
public void test2(){
Comparator<Integer> com=(x,y)->Integer.compare(x,y);
TreeSet<Integer> ts=new TreeSet<>(com);
}
/**-------------------------------------------分割线---------------------------------------------------------**/
//准备数据
List<Employee> employees= Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",38,5555.99),
new Employee("王五",50,6666.99),
new Employee("赵六",16,3333.99),
new Employee("田七",8,7777.99)
);
//需求:获取年龄大于34的员工信息,使用传统方式
public List<Employee> filterEmployee1(List<Employee> list){
List<Employee> emps=new ArrayList<>();
for (Employee emp:list) {
if (emp.getAge()>34){
emps.add(emp);
}
}
return emps;
}
@Test
public void test3(){
List<Employee> list=filterEmployee1(employees);
for (Employee employee:list) {
System.out.println(employee);
}
}
//需求:获取工资大于5000的员工信息,使用传统方式
public List<Employee> filterEmployee2(List<Employee> list){
List<Employee> emps=new ArrayList<>();
for (Employee emp:list) {
if (emp.getSalary()>5000){
emps.add(emp);
}
}
return emps;
}
@Test
public void test4(){
List<Employee> list=filterEmployee2(employees);
for (Employee employee:list) {
System.out.println(employee);
}
}
/** -------------------------------------------------------分割线---------------------------------------------------------------**/
public List<Employee> filterEmployee(List<Employee> list, MyPredicate<Employee> mp){
List<Employee> emps=new ArrayList<>();
for (Employee employee:list) {
if(mp.test(employee)){
emps.add(employee);
}
}
return emps;
}
/**优化方式一:使用该策略设计模式,创建一个接口,根据不同的需求来实现这个接口,缺点是当需求增加了,类的数量也在增加
*/
@Test
public void test5(){
List<Employee> list=filterEmployee(employees,new FilterEmployeeByAge());
for (Employee employee:list){
System.out.println(employee);
}
System.out.println("----------------------");
List<Employee> list2=filterEmployee(employees,new FilterEmployeeBySalary());
for (Employee employee:list2){
System.out.println(employee);
}
}
//优化方式二:使用匿名内部类来实现接口
public void test6(){
List<Employee> list=filterEmployee(employees, new MyPredicate<Employee>() {
@Override
public boolean test(Employee employee) {
return employee.getSalary()<5000;
}
});
for (Employee employee:list){
System.out.println(employee);
}
}
//使用lambda表达式
@Test
public void test7(){
List<Employee> list=filterEmployee(employees,(e)->e.getSalary()<5000);
list.forEach(System.out::println);
}
//使用stream API
@Test
public void test8(){
employees.stream()
.filter((e)->e.getSalary()>=5000)
.forEach(System.out::println);
}
}
- Employee.java实体类
package com.xuzhi.entity;
import lombok.*;
/**
* Author: 徐志
* Date: 2020/8/1 10:10
*/
@Setter
@Getter
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private String name;
private int age;
private double salary;
}
- MyPredicate.java
package com.xuzhi.predicate;
/**
* Author: 徐志
* Date: 2020/8/1 10:37
*/
public interface MyPredicate<T> {
public boolean test(T t);
}
- FilterEmployeeByAge.java类
package com.xuzhi.predicate;
import com.xuzhi.entity.Employee;
/**
* Author: 徐志
* Date: 2020/8/1 10:39
*/
public class FilterEmployeeByAge implements MyPredicate<Employee> {
@Override
public boolean test(Employee employee) {
return employee.getAge()>34;
}
}
- FilterEmployeeBySalary.java
package com.xuzhi.predicate;
import com.xuzhi.entity.Employee;
/**
* Author: 徐志
* Date: 2020/8/1 10:38
*/
public class FilterEmployeeBySalary implements MyPredicate<Employee> {
@Override
public boolean test(Employee employee) {
return employee.getSalary()>5000;
}
}
3、lambda表达式基础语法
- lambda的基本语法:“->”该操作符称为箭头操作符或lambda操作符,箭头操作符将表达式拆为两部分
- 左侧: lambda表达式需要的参数列表,即接口中抽象方法的参数列表
- 右侧: lambda表达式所需执行的功能
- lambda表达式参数类型可以不写
- lambada表达式需要函数式接口支持
- 函数式接口:接口里面只有一个抽象方法,可以使用@FuncutionalInterface注解修饰检查接口是否为函数式接口
package com.xuzhi.lambda;
/**
* Author: 徐志
* Date: 2020/8/1 11:10
*/
import com.xuzhi.function.MyFunction;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
public class TestLambda2 {
//使用匿名内部类
@Test
public void test1(){
Runnable r=new Runnable() {
@Override
public void run() {
System.out.println("hello world");
}
};
System.out.println("----------------------------------------------------");
/*
语法一:无参数无返回值
*/
Runnable r1=()-> System.out.println("hello lambda");
}
@Test
public void test2(){
/*
语法二:有一个参数无返回值
*/
Consumer<String> con=(x)->System.out.println(x);
con.accept("笨蛋");
}
@Test
public void test3(){
/*
语法三:两个参数,有返回值,多条语句
*/
Comparator<Integer> com=(x,y)->{
System.out.println("hello");
return Integer.compare(x,y);
};
/*
语法四:两个参数,有返回值,一条语句
*/
Comparator<Integer> com2=(x,y)-> Integer.compare(x,y);
}
//需求:对一个数进行操作
@Test
public void test4(){
Integer result= operation(100,(x)->x*x);
System.out.println(result);
System.out.println(operation(100,(x)->x+x));
}
public Integer operation(Integer num, MyFunction mf){
return mf.getValue(num);
}
}
4、四大函数式接口
- 消费型接口:有参数无返回值
- 供给型接口:无参数有返回值
- 函数型接口:有参数有返回值
- 断定型接口:有参数返回值为布尔
package com.xuzhi.lambda;
/**
* Author: 徐志
* Date: 2020/8/1 13:55
*/
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* 四大核心函数式接口
*
* Consumer<T> : 消费型接口
* void accept (T t)
* Supplier<T>: 供给型接口
* T get()
* Function <T,R>: 函数型接口
* R apply(T t)
* Predicate <T> : 断定型接口
* boolean test(T t)
*/
public class TestLambda3 {
//消费型接口
@Test
public void test1(){
happy(1000,(m)-> System.out.println("消费了"+m));
}
public void happy(double money, Consumer<Double> con){
con.accept(money);
}
//供给型接口
@Test
public void test2(){
List<Integer> numList = getNumList(10, () -> (int) Math.random() * 100);
for (Integer n:numList) {
System.out.println(n);
}
}
public List<Integer> getNumList(int num, Supplier<Integer> sup){
List<Integer> list=new ArrayList<>();
for (int i=0;i<num;i++){
Integer integer = sup.get();
list.add(integer);
}
return list;
}
//函数型接口
@Test
public void test3(){
String s = strHandeler("aaa", (x) -> x.toUpperCase());
System.out.println(s);
}
public String strHandeler(String str, Function<String,String> fun){
return fun.apply(str);
}
//断言型接口
public void test4(){
List<String> list= Arrays.asList("he","aaaaa","ddddd","ddd","fffa");
List<String> strings = filterStr(list, (s) -> s.length() > 3);
for (String s: strings) {
System.out.println(s);
}
}
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> strList=new ArrayList<>();
for (String str : strList) {
if (pre.test(str)){
strList.add(str);
}
}
return strList;
}
}
5、方法引用和构造器引用
方法引用:如果Lambda体中的内容已有方法实现,我们则可以使用方法引用
语法:
- 对象实例::方法名
- 类名::静态方法名
- 类名::实例方法名
注意:
1、lambda中调用的方法的参数列表与返回值类型,要与函数式接口中的抽象方法的函数列表和返回值类型一致
2、 若lambda参数列表中的第一个参数是实例方法的调用者,第二个参数是实例方法的参数是,可以使用类名::方法名
package com.xuzhi.lambda;
/**
* Author: 徐志
* Date: 2020/8/1 14:24
*/
import com.xuzhi.entity.Employee;
import org.junit.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 方法引用:如果Lambda体中的内容已有方法实现,我们则可以使用方法引用
对象实例::方法名
类::静态方法名
类::实例方法名
lambda中调用的方法的参数列表与返回值类型,要与函数式接口中的抽象方法的函数列表和返回值类型一致
若lambda参数列表中的第一个参数是实例方法的调用者,第二个参数是实例方法的参数是,可以使用类名::方法名
*/
public class TestMethodRef {
//对象实例::方法名
@Test
public void test1(){
Consumer<String> con=(x)-> System.out.println(x);
PrintStream ps= System.out;
Consumer<String> con1=ps::println;
}
@Test
public void test2(){
Employee emp=new Employee();
Supplier<String> sup=()->emp.getName();
String s = sup.get();
System.out.println(s);
Supplier<Integer> sup2=emp::getAge;
Integer integer = sup2.get();
System.out.println(integer);
}
//静态方法,类::静态方法名
@Test
public void test3(){
Comparator<Integer> com=(x,y)->Integer.compare(x,y);
Comparator<Integer> com1=Integer::compare;
}
//类::实例方法名
@Test
public void test4(){
BiPredicate<String,String> bp=(x,y)->x.equals(y);
BiPredicate<String,String> bp2=String::equals;
}
//构造器引用:需要调用的构造器和接口中一致
public void test5(){
Supplier<Employee> sup=()->new Employee();
Supplier<Employee> sup2=Employee::new;
}
//数组引用
@Test
public void test6(){
Function<Integer,String[]> fun=(x)->new String[x];
String[] strs=fun.apply(10);
System.out.println(strs.length);
Function<Integer,String[]> fun2=String[]::new;
}
}
6、lambda表达式小练习
package com.xuzhi.lambda;
import com.xuzhi.entity.Employee;
import com.xuzhi.function.NumFunction;
import com.xuzhi.function.StrFunction;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Author: 徐志
* Date: 2020/8/1 11:48
*/
public class Zuoye {
List<Employee> employees= Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",38,5555.99),
new Employee("王五",50,6666.99),
new Employee("赵六",16,3333.99),
new Employee("田七",8,7777.99)
);
/**
* 调用Collections.sort()方法,定制排序EMployee,先按照年龄比,年龄相同按照姓名比
* 使用lambda表达式
*/
@Test
public void test1(){
Collections.sort(employees,(e1,e2)->{
if (e1.getAge()==e2.getAge()){
return e1.getName().compareTo(e2.getName());
}else{
return Integer.compare(e1.getAge(),e2.getAge());
}
});
for (Employee employee:employees){
System.out.println(employee);
}
}
//处理字符串,转大写
@Test
public void test2(){
String s = srHandler("haha", (str) -> str.toUpperCase());
System.out.println(s);
}
public String srHandler(String str, StrFunction sf){
return sf.getValue(str);
}
//两个数操作
@Test
public void test3(){
opreation(100L,200L,(x,y)->x+y);
opreation(100L,200L,(x,y)->x*y);
}
public void opreation(Long l1, Long l2, NumFunction<Long,Long> mf){
System.out.println(mf.getValue(l1,l2));
}
}
总结
本人学习java8新特性观看的是B站的是尚硅谷的学习视频,所有代码均亲手所敲,在这里感谢尚硅谷。现在lambda表示式的使用也是非常的广泛,我们有必要掌握这些这些java新的特性,尤其是Spring框架中lambda表达式和Stream流的应用也是非常的广泛。工作中也会有应用。附上本人微信公众号二维码,希望大家关注,一起学习进步