目录
Lambda表达式
一、为什么要使用Lambda表达式
Lambda是一个匿名函数,我们可以吧Lambda表达式理解为是一段可以传递的代码(将代码向数据一样进行传递)
举例:
package com.sofwin.jdk8.lambda;
import org.junit.Test;
import java.util.Comparator;
/**
* @packageName: com.sofwin.jdk8.lambda
* @author: wentao
* @date: 2022/10/18 20:51
* @version: 1.0
* @email 1660420659@qq.com
* @description: Lambda表达式的使用举例
*/
public class LambdaTest {
@Test
public void test01() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("启动run的线程");
}
};
r1.run();
Runnable r2= () -> System.out.println("lambda表示");
r2.run();
}
@Test
public void test02(){
Comparator<Integer> com1=new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
int compare = com1.compare(12, 21);
System.out.println(compare);
System.out.println("---------------------");
//Lambda表达式
Comparator<Integer> com2 =(o1,o2) ->Integer.compare(o1,o2);
int compare2 = com1.compare(32, 21);
System.out.println(compare2);
System.out.println("-----------------");
//方法引用
Comparator<Integer> com3 = Integer::compareTo;
int compare3 = com1.compare(32, 21);
System.out.println(compare3);
}
}
通过上面代码的对比,我们发现Lambda表达式的确简化了代码
二、Lambda表达式的使用
Lambda表达式的六种情况
package com.sofwin.jdk8.lambda;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.function.Consumer;
/**
* @packageName: com.sofwin.jdk8.lambda
* @author: wentao
* @date: 2022/10/18 21:07
* @version: 1.0
* @email 1660420659@qq.com
* @description: Lambda表达式的使用
* <p>
* 1. (o1,o2) ->Integer.compare(o1,o2)
* 2.格式:
* ->: lambda操作符 或者 箭头操作符
* ->的左边: 叫形参列表 ---也就是原先接口中抽象方法的形参列表
* ->的右边: lambda体 ---其实就是重写抽象方法的方法体
* 3. Lambda方法的使用 六种格式
* 总结:
* ->左边: Lambda形参列表的参数类型可以省略;
* Lambda形参个数只有一个 一对小括号可以省略
* 如果形参没有或者有二个及以上 小括号就不能省略了
* ->右边: Lambda体应该使用{}包裹
* 如果Lambda体只有一条执行语句 就可以省略{} 以及return关键字
* 如果多于一条一定要有{} 、有return也不能省略
*
* 4.Lambda表达式的本质:作为左边接口的实例(对象)
*
* 5.要求必须是函数式接口(下面讲)
*/
public class LambdaTest2 {
//语法格式一:无参,无返回值
@Test
public void test01() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("111");
}
};
Runnable r2 = () -> {
System.out.println("2222");
};
}
//语法格式二:Lambda 需要一个参数,但是没有返回值。
@Test
public void test02() {
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("www");
Consumer<String> con2 = (String s) -> {
System.out.println(s);
};
con2.accept("qqq");
}
//语法格式三:数据类型可以省略,因为可以由编译器推断得出,称为 类型推断、
@Test
public void test03() {
Consumer<String> con2 = (String s) -> {
System.out.println(s);
};
//数据类型是可以省略的,因为可以有编译器推断得出
Consumer<String> con1 = (s) -> {
System.out.println(s);
};
//类型推断以前也有
ArrayList<String> list = new ArrayList<>();
int[] arr = {1, 2, 3};
}
//语法格式四:如果Lambda若只需要一个参数,参数的小括号可以省略
@Test
public void test04() {
Consumer<String> con1 = (s) -> {
System.out.println(s);
};
//如果参数只有一个可以省略括号
Consumer<String> con2 = s -> {
System.out.println(s);
};
}
//语法格式五:Lambda表达式需要两个或者以上的参数,多条执行语句,并且可以有返回值
@Test
public void test5() {
Comparator<Integer> c1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
};
Comparator<Integer> c2 = (o1, o2) -> {
System.out.println(o1);
return o1.compareTo(o2);
};
}
//语法格式六:如果Lambda体中只要一条语句,return和大括号都可以省略
@Test
public void test06() {
Comparator<Integer> c1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
};
Comparator<Integer> c2 = (o1, o2) -> o1.compareTo(o2);
}
}
三、函数式(Function)接口
Lambda表达式针对的接口,给接口提供具体的实现类对象的时候,我们用到了Lambda表达式
并且简化了对接口的抽象方法的实现代码
但是使用Lambda表达式的接口有一定要求的---只能有一个抽象方法 我们也称这种只有一个抽象方法的接口叫做函数式接口 (接口中方法都为抽象方法)
四、方法引用与构造器引用
1.方法引用
方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例。
Employee类
package com.sofwin.java2;
/**
* @packageName: com.sofwin.java2
* @author: wentao
* @date: 2022/10/18 22:35
* @version: 1.0
* @email 1660420659@qq.com
* @description: TODO
*/
public class Employee {
private int id;
private String name;
private int age;
private double salary;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Employee(){
}
public Employee(int id){
this.id = id;
}
public Employee(int id, String name){
this.id = id;
this.name = name;
}
public Employee(int id, String name, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
if (id != employee.id) return false;
if (age != employee.age) return false;
if (Double.compare(employee.salary, salary) != 0) return false;
return name != null ? name.equals(employee.name) : employee.name == null;
}
@Override
public int hashCode() {
int result;
long temp;
result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + age;
temp = Double.doubleToLongBits(salary);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
}
方法引用的三种格式
分别为 对象::实例方法、类::静态方法、类::实例方法
package com.sofwin.java2;
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;
/**
* @packageName: com.sofwin.java2
* @author: wentao
* @date: 2022/10/18 22:42
* @version: 1.0
* @email 1660420659@qq.com
* @description: 方法引用的使用
*
* 1.使用情景: 当要传递给Lambda体的操作,已经有时限的方法了,可以使用方法引用!
*
* 2.方法引用,本质上就是Lambda表达式,而Lambda表达式是作为函数式接口的实例。所以
* 方法引用也是函数式接口的实例。、
*
* 3. 使用格式 类(或对象) ::方法名
*
* 4.具体分为如下的三种情况
* 情况1 对象::非静态方法名(实例方法)
* 情况2 类::静态方法、
* 情况3 类::非静态方法(注意哦 没有写错就是类调用非静态方法)
*
* 5.方法引用的使用要求:要求接口中抽象方法的形参列表和返回值类型
* 与方法引用的方法的形参列表和返回值类型都要相同(仅针对情况1和情况2)
*
*/
public class MethodTest {
//情况1 对象::实例方法
//Consumer中的void accept(T t)
//PrintStream中的 void println(T t)
@Test
public void test() {
Consumer<String> con1 =str -> System.out.println(str);
con1.accept("北京");
System.out.println("============方法引用================");
PrintStream ps=System.out;
Consumer<String> cons2 = ps::println;
//类型省略 参数下面写了 也省略
cons2.accept("北京");
}
//Supplier中的T get()
//Employe中的 String getName();
@Test
public void test02() {
Employee employee=new Employee(1001,"tom",23,5600);
Supplier<String> sup1 = () -> employee.getName();
System.out.println(sup1.get());
Supplier<String> sup2 = employee::getName;
System.out.println(sup2.get());
}
//情况二: 类::静态方法
//Compartor 中 int compare(T t1,T t2)
//Integer 中 int compare(T t1,T t2)
@Test
public void test03() {
Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);
System.out.println(com1.compare(12,21));
Comparator<Integer> com2 =Integer::compareTo;
System.out.println(com2.compare(12, 10));
}
//Function R apply(T t)
//Math Long round(Double d)
@Test
public void test04() {
Function<Double,Long> fun = d -> Math.round(d);
Long apply = fun.apply(11.1);
System.out.println(apply);
Function<Double,Long> fun2 =Math::round;
Long apply1 = fun2.apply(2.9);
System.out.println(apply1);
}
//情况三 类::实例方法
//Comparator中int compare(T t1, T t2)
//String int t1.compareTo(t2)
//代表的是t1调用compareTo方法 与t2 比较
@Test
public void test05() {
Comparator<String> com1 =(s1,s2) -> s1.compareTo(s2);
int compare = com1.compare("abc", "abd");
System.out.println(compare);
Comparator<String> com2 =String::compareTo;
System.out.println(com2.compare("abc", "abn"));
}
//BiPredicate中的 boolean test(T t1,T t2);
//String中的boolean t1.equals(t2)
@Test
public void test06() {
BiPredicate<String,String> bi=(t1,t2) -> t1.equals(t2);
System.out.println(bi.test("www", "qqq"));
BiPredicate<String,String> bi2=String::equals;
System.out.println(bi2.test("ww", "ww"));
}
//Function中 R apply(T t)
//Employee中String getName()
@Test
public void test07() {
Function<Employee,String> f1 = t -> t.getName();
System.out.println(f1.apply(new Employee(1103, "jeey", 11, 11134)));
Function<Employee,String> f2 = Employee::getName;
System.out.println(f2.apply(new Employee(1106, "winter", 23, 113.6)));
}
}
2.构造器引用和数组引用
package com.sofwin.java2;
import org.junit.Test;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* @packageName: com.sofwin.java2
* @author: wentao
* @date: 2022/10/19 21:53
* @version: 1.0
* @email 1660420659@qq.com
* @description: 构造器引用
*
* 一、构造器引用
* 和方法引用类似
* 函数式接口的抽象方法的形参类别和构造器的形参列表一致
* 抽象方法的返回值类型即为构造器所属类的类型
* 二、数组引用
* 大家可以把数组看做是一个特殊的类,则写法与构造器引用就大致相同了
*/
public class ConstructorRefTest {
//构造器引用
//Supplier中的 T get()
// Employee的空串构造器 Employee()
@Test
public void test01() {
Supplier<Employee> sup = new Supplier<Employee>() {
@Override
public Employee get() {
return new Employee();
}
};
Supplier<Employee> sup1 = () -> new Employee();
Supplier<Employee> sup2 = Employee::new;
}
//Function 中的 R apply(T t)
// Employee的一个参数构造器 Employee(int id)
@Test
public void test02() {
Function<Integer,Employee> f1 = t -> new Employee(t);
Function<Integer,Employee> f2 = Employee::new;
}
//BiFunction 中 R apply(T t,U u)
//Employee的两个参数的构造器 Employee(int id,String name)\
@Test
public void test03() {
BiFunction<Integer,String,Employee> bif = (t,u) -> new Employee(t,u);
BiFunction<Integer,String,Employee> bif2 = Employee::new;
}
//二、数组引用
//Function 中的R apply(T t)
@Test
public void test04() {
Function<Integer,String[]> fu = t -> new String[t];
Function<Integer,String[]> fu2 = String[]::new;
}
}
五、Java内置函数式接口
1. 集合遍历Consumer
package com.andyliu.demo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
public class Program1 {
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.add(new User(1,"admin1"));
users.add(new User(10,"admin10"));
users.add(new User(8,"admin8"));
users.add(new User(7,"admin7"));
users.add(new User(6,"admin6"));
users.add(new User(20,"admin20"));
// 传统集合遍历
// for
for(int i=0;i<users.size();i++){
System.out.println(users.get(i));
}
System.out.println("********以上是传统集合遍历************");
// 迭代器
Iterator<User> iterator = users.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("*********迭代器遍历*************");
// foreach
for(User user:users){
System.out.println(user);
}
System.out.println("***************foreach遍历**********");
// list的foreach方法
users.forEach(u-> System.out.println(u));
System.out.println("********lambda遍历*************");
users.forEach(System.out::println);
}
}
2. 集合排序Comparator
package com.andyliu.demo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
public class Program1 {
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.add(new User(1,"admin1"));
users.add(new User(10,"admin10"));
users.add(new User(8,"admin8"));
users.add(new User(7,"admin7"));
users.add(new User(6,"admin6"));
users.add(new User(20,"admin20"));
// 按id升序排列
users.sort((o1,o2)->o1.getId()-o2.getId());
users.forEach(System.out::println);
}
}