18.JDK8
18.1 Lambda表达式
18.1.1 什么是Lambda表达式
- 概念:允许把函数作为一个方法的参数。(函数作为参数传递到方法中)
<函数式接口> <变量名> = (参数1 , 参数2 …) -> {
//方法体
}
public class TestLambdas {
public static void main(String[] args) {
//1.匿名内部类会生成.class文件
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("这是一个子线程");
}
});
t1.start();
//lambda表达式简写,不会生成单独的内部类文件
Runnable task = () -> {
System.out.println("这个也是一个子线程");
};
Thread t2 = new Thread(task);
t2.start();
new Thread( () -> {
System.out.println("这个还是一个子线程");
} ).start();
}
}
输出结果:
这是一个子线程
这个也是一个子线程
这个还是一个子线程
18.1.2 注意事项
-
新的操作符 -> (箭头操作符)
(参数1 , 参数2) -> 表示参数列表
-> { }方法体 -
形参列表的数据类型会自动推动
-
如果形参列表为空,只需保留()
-
如果形参只有1个,()可以省略,只要参数名字即可
-
如果执行语句只有1句,且无返回值,{}可以省略;
-
若有返回值,仍想省略{},return也省略。保证执行语句只有1句
-
Lambda表达式不会生成单独的内部类文件
-
Lambda访问局部变量时,变量要修饰final,如果没加,会自动添加
员工类:
public class Employee {
private String name;
private int age;
private String sex;
private double salary;
public Employee() {
super();
}
public Employee(String name, int age, String sex, double salary) {
super();
this.name = name;
this.age = age;
this.sex = sex;
this.salary = salary;
}
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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee [name=" + name + ", age=" + age + ", sex=" + sex + ", salary=" + salary + "]";
}
}
断言型接口:
/*
* 规则
* 能力
* */
//需求只是需要对关键信息进行判断,返回布尔值,则可以为其定义普适性的接口
public interface MyPredicate<T> {
boolean test(T t);
}
import java.util.ArrayList;
import java.util.List;
public class TestEmployee {
public static void main(String[] args) {
List<Employee> list = new ArrayList<Employee>();
list.add(new Employee("Tom",32,"male",28000));
list.add(new Employee("Jack",25,"male",18000));
list.add(new Employee("Alex",22,"male",13000));
list.add(new Employee("Annie",21,"female",9000));
list.add(new Employee("Rose",20,"male",8000));
//获得年龄大于等于25的员工
// List<Employee> ageList = getAgeEmployee(list);
// for (Employee e : ageList) {
// System.out.println(e);
// }
// System.out.println();
//获得工资大于10000的员工
// List<Employee> salaryList = getSalaryEmployee(list);
// for (Employee e : salaryList) {
// System.out.println(e);
// }
// System.out.println();
//基本的实现需求的操作
//获得年龄大于25且工资大于10000的员工 通过普适性的方法实现需求
List<Employee> prelist = getAgeAndSalary(list,new MyPredicate<Employee>() {
@Override
public boolean test(Employee t) {
if(t.getAge() >= 25 && t.getSalary() >= 10000) {
return true;
}
return false;
}
});
for (Employee employee : prelist) {
System.out.println(employee);
}
System.out.println();
System.out.println("----lambda 工资大于等于10000年龄大于等于25----");
//使用lambda表达式可以简写为
List<Employee> prelist2 = getAgeAndSalary(list, (e) ->{
return e.getAge()>=25 && e.getSalary()>=10000;
});
//甚至还能简写为
List<Employee> prelist3 = getAgeAndSalary(list, e -> e.getAge() >= 25 && e.getSalary() >= 10000);
for (Employee employee : prelist2) {
System.out.println(employee);
}
System.out.println("-------------------------------------\n");
//使用普适性接口和lambda表达式简写最上面两个
System.out.println("---lambda 年龄大于等于25的---");
List<Employee> prelist4 = getAgeAndSalary(list, (e) -> {//通用的简写方式
return e.getAge()>=25;
});
for (Employee employee : prelist4) {
System.out.println(employee);
}
System.out.println();
System.out.println("---lambda 工资大于等于10000的---");
//当形参只有一个,且执行语句只有一句,则可以省略() {;}
List<Employee> prelist5 = getAgeAndSalary(list, e -> e.getSalary()>=10000);
for (Employee employee : prelist5) {
System.out.println(employee);
}
System.out.println();
//stream简写,更加简化。。。
System.out.println("-------------stream相关的实现输出工资大于等于10000的-----------------");
list.stream().filter( (e)->e.getSalary() >= 10000 ).forEach(System.out::println);
}
//实现需求的普通的写法
// public static List<Employee> getAgeEmployee(List<Employee> list){
//
// List<Employee> newlist = new ArrayList<>();
// for(Employee e : list) {
// if(e.getAge() >= 25) {
// newlist.add(e);
// }
// }
// return newlist;
// }
// public static List<Employee> getSalaryEmployee(List<Employee> list){
//
// List<Employee> newlist = new ArrayList<>();
// for(Employee e : list) {
// if(e.getSalary() >= 10000) {
// newlist.add(e);
// }
// }
// return newlist;
// }
//使用Predicate接口实现 对不同需求的通用方法
public static List<Employee> getAgeAndSalary(List<Employee> list , MyPredicate<Employee> predicate){
List<Employee> newlist = new ArrayList<>();
for (Employee e : list) {
if(predicate.test(e)) {//调用规则!只关心结果,不关心过程
newlist.add(e);
}
}
return newlist;
}
}
输出结果:
Employee [name=Tom, age=32, sex=male, salary=28000.0]
Employee [name=Jack, age=25, sex=male, salary=18000.0]
----lambda 工资大于等于10000年龄大于等于25----
Employee [name=Tom, age=32, sex=male, salary=28000.0]
Employee [name=Jack, age=25, sex=male, salary=18000.0]
-------------------------------------
---lambda 年龄大于等于25的---
Employee [name=Tom, age=32, sex=male, salary=28000.0]
Employee [name=Jack, age=25, sex=male, salary=18000.0]
---lambda 工资大于等于10000的---
Employee [name=Tom, age=32, sex=male, salary=28000.0]
Employee [name=Jack, age=25, sex=male, salary=18000.0]
Employee [name=Alex, age=22, sex=male, salary=13000.0]
-------------stream相关的实现输出工资大于等于10000的-----------------
Employee [name=Tom, age=32, sex=male, salary=28000.0]
Employee [name=Jack, age=25, sex=male, salary=18000.0]
Employee [name=Alex, age=22, sex=male, salary=13000.0]
18.1.3 函数式接口
- 如果一个接口只有一个抽象方法,则该接口称为函数式接口;
- 为了确保接口达到要求,可以添加@FuntionalInterface注解;
内置四个核心函数式接口:
- Consumer 消费型接口 void accept(T t);
import java.util.function.Consumer;
public class TestConsumer {
public static void main(String[] args) {
m1(1000,(a)->System.out.println("今天挣了:"+a+"rmb"));
m2(10 , (a)->{
for(int i = 1;i<=a;i++) {
System.out.println(i);
}
});
}
//Consumer接口是只有一个 无返回值,单个形参 的接口,可用于使用lambda表达式
public static void m1(double money , Consumer<Double> consumer) {
consumer.accept(money);
}
public static void m2(int num , Consumer<Integer> consumer) {
consumer.accept(num);
}
}
输出结果:
今天挣了:1000.0rmb
1
2
3
4
5
6
7
8
9
10
- Supplier 共计型接口 T get();
import java.util.Random;
import java.util.function.Supplier;
public class TestSupplier {
public static void main(String[] args) {
//使用Supplier接口,实现一个通用型的方法,调用该方法时,可以使用lambda表达式进行简写
int sum = getSum(10, ()->new Random().nextInt(100));
System.out.println("的和是:"+sum);
//使用Supplier接口和lambda表达式,进行自定义功能
Supplier<Integer> sup = () -> {
int count = 0 ;
for(int i = 1 ; i<=50; i++) {
count += i;
}
return count;
};
System.out.println("1~50的和是:"+ sup.get());
}
//Supplier接口是一个 有一个对象类型,无参的抽象方法 的接口
public static int getSum(int num , Supplier<Integer> supplier) {
int sum = 0 ;
for(int i = 1 ; i<= num ; i++) {
System.out.print(supplier.get()+" ");
sum += supplier.get();
}
return sum;
}
}
输出结果:
51 23 36 14 98 97 2 37 45 20 的和是:601
1~50的和是:1275
- Function<T,R> 函数型接口 R apply(T t);
import java.util.function.Function;
public class TestFunction {
public static void main(String[] args) {
//使用Function接口,通过lambda表达式实现接口,自定义实现方法
String up = stringUpper("hello" , (s) -> s.toUpperCase() );
System.out.println(up);
String tirms = stringUpper(" Alex " , (s) -> s.trim());
System.out.println(tirms);
}
//Function接口是一个 只有个形参、一个返回值的方法的 的接口。
//使用时,以Function<T,R>的形式使用,传入的形参是T,返回的是R,相当于对T进行操作,以R的形式返回
public static String stringUpper(String s , Function<String ,String> fun) {
return fun.apply(s);
}
}
输出结果:
HELLO
Alex
- Predicate 断言型接口 boolean test(T t);
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class TestPredicate {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("tom");
list.add("jack");
list.add("alex");
list.add("rose");
list.add("annie");
//使用Predicate接口,通过lambda表达式,自定义过滤条件
List<String> f = filter(list , (s) -> s.startsWith("a"));
for (String s : f) {
System.out.println(s);
}
}
//Predicate接口是 只有一个 单参数、布尔类型返回值 的方法的接口
public static List<String> filter(List<String> list , Predicate<String> p){
List<String> list2 = new ArrayList<String>();
for(String s : list) {
if(p.test(s)) {
list2.add(s);
}
}
return list2;
}
}
输出结果:
alex
annie
18.1.4 方法引用
- 方法引用是Lambda表达式的一种简写形式,如果Lambda表达式方法体中只是调用一个特定的已存在的方法,则可以使用方法引用;
- 使用 :: 操作符将对象或类和方法名的名字分隔开来;
对象 :: 实例方法
类 :: 静态方法
类 :: 实例方法
类 :: new - 注意:调用的方法参数列表与返回值 类型,要与函数型接口中的方法参数列表与返回值类型一致;
import java.util.Comparator;
import java.util.TreeSet;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import com.qf.Day35.Employee;
public class TestMethodRef {
public static void main(String[] args) {
//Lambda表达式简化了匿名内部类,方法引用简化了Lambda表达式
//1.对象::方法名
//平常的写法
Consumer<String> con = (s) -> System.out.println(s);
con.accept("hello");
//使用方法引用的写法
Consumer<String> con2 = System.out::println;
con2.accept("world");
Employee e = new Employee("alex" , 22 , "male" , 15000D);
Supplier<String> sup1 = () -> e.getName();//lambda
System.out.println(sup1.get());
Supplier<String> sup2 = e::getName;//与上同理,方法引用的写法
System.out.println(sup2.get());
//2.类名::静态方法(不常用)
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);//lambda
int result = com.compare(1, 2);
System.out.println(result);
Comparator<Integer> com2 = Integer::compare;//方法引用的写法
TreeSet<Integer> ts = new TreeSet<>(com);//制定TreeSet的排序规则
//3.类名::实例方法名
//Function<T,R> R.apply(T t);
Function<Employee , String> fun = emp -> emp.getName(); //lambda
String name = fun.apply(e);
System.out.println(name);
Function<Employee , String> fun2 = Employee::getName;//方法引用
//4.类::new 类名::构造方法(不常用)
Supplier<Employee> supp = () -> new Employee();//lambda
Employee empl = supp.get();
System.out.println(empl);
Supplier<Employee> supp2 = Employee::new;//方法引用
}
}
输出结果:
hello
world
alex
alex
-1
alex
Employee [name=null, age=0, sex=null, salary=0.0]