先来一段传统的匿名内部类调用程序
//定义一个数学接口
public interface Maths {
//定义一个计算的接口方法
int calc(int a, int b);
}
//测试类
public class MathsTester {
//定义一个打印计算结果的方法
public static void printCalcResult(int a,int b,Maths maths){
System.out.println(maths.calc(a, b));
}
}
//传统的匿名内部类使用方法
public static void main(String[] args) {
//定义两个数
int a = 10;
int b = 5;
//两个数相加;
MathsTester.printCalcResult(a, b, new Maths() {
@Override
public int calc(int a, int b) {
return a + b;
}
});
//两个数相减;
MathsTester.printCalcResult(a, b, new Maths() {
@Override
public int calc(int a, int b) {
return a * b;
}
});
}
使用Lambda表达式后
public static void main(String[] args) {
//定义两个数
int a = 10;
int b = 5;
//使用lambda表达式定义4个接口的实现类,(num1, num2):括号中的参数不能与外面的变量a和b重名
Maths add = (num1, num2) -> num1 + num2; //加
Maths sub = (num1, num2) -> num1 + num2; //减
//打印计算结果
MathsTester.printCalcResult(a, b, add);
MathsTester.printCalcResult(a, b, sub);
//简单的写法
MathsTester.printCalcResult(a, b, (num1, num2) -> num1 * num2);
MathsTester.printCalcResult(a, b, (num1, num2) -> num1 / num2);
//先判断,在选择如何计算,有多行语句时,要使用花括号{}
MathsTester.printCalcResult(a, b, (num1, num2) -> {
if (num1 > num2) {
return num1 - num2;
} else {
return num1 + num2;
}
});
//直接调用接口方法
System.out.println(add.calc(a, b));
System.out.println(add.calc(a, b));
//无参数lambda表达式:() -> xxx
//仅当接口的方法有且仅有一个抽象方法时,才能使用lambda表达式
}
函数式接口
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换为 lambda 表达式
//使用注解定义该接口是一个函数式接口,也可以不加注解,只要遵循函数式接口的定义就可以 了,使用注解java编译器会自动识别错误
@FunctionalInterface
public interface Hello {
//抽象方法有且只有一个
void hello();
//默认方法,jdk8以前是不允许在接口中的方法有方法体的,可以定义多个默认方法
default void hi(){
System.out.println("hi..........");
}
default void o(){
System.out.println("o...........");
}
//可以定义静态方法
static void he(){
System.out.println("he..........");
}
}
//接口实现类
public class HelloImpl implements Hello {
//接口抽象方法实现
@Override
public void hello() {
// TODO Auto-generated method stub
}
//可以重写父接口的默认方法,也可以不重写,Hello.o()方法,我们就没重写
@Override
public void hi() {
Hello.super.hi(); //调用父接口的实现
System.out.println("..........hi");
}
public static void main(String[] args) {
//常规接口实例化
Hello hello = new HelloImpl();
hello.hi();
//lambda表达式实例化接口
Hello _hello = () -> System.out.println("ho......");
_hello.hello();
_hello.o();
//调用父接口的静态方法
Hello.he();
}
}
//当MyClass和Myfun(default方法)都存在相同方法时,SubClass优先使用MyClass的方法
public class SubClass extends MyClass implements Myfun {
}
//当Myfun1和Myfun2都存在相同方法时(default方法),SubClass必须指定重写谁的方法
public class SubClass implements Myfun1,Myfun2 {
}
内置的函数式接口
java.util.function 包下含了很多函数式接口,这里我们主要讲解四个核心接口,其他接口依葫画瓢
@FunctionalInterface
public interface Consumer<T> {
void accept(T t); //表示接受单个输入参数并且不返回结果的操作
......
}
@FunctionalInterface
public interface Supplier<T> {
T get(); //获得结果
}
@FunctionalInterface
public interface Function<T, R> {
R apply(T t); //输入一个参数,返回一个结果R
......
}
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t); //输入一个参数,返回布尔值
......
}
public class Tester {
//Consumer<T>
public void happy(double money, Consumer<Double> consumer){
consumer.accept(money);
}
@Test
public void testHappy(){
happy(1000, (m) -> System.out.println("这次去happy,一共消费了"+m+"元"));
}
//Supplier<T>
public List<String> fillList(int size,Supplier<String> supplier){
List<String> list = new ArrayList<String>();
for (int i = 0; i < size; i++) {
list.add(supplier.get());
}
return list;
}
@Test
public void testFillList(){
System.out.println(fillList(10, () -> Math.random() + ""));
}
//Function<T, R>
public String strHandler(String str, Function<String, String> fun){
return fun.apply(str);
}
@Test
public void testStrHandler(){
System.out.println(strHandler("\t\t\t清除两端空格 ", (str) -> str.trim()));
}
//Predicate<T>
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> newList = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
if(pre.test(list.get(i))){
newList.add(list.get(i));
}
}
return newList;
}
@Test
public void testFilterStr(){
List<String> list = new ArrayList<>(Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok"));
System.out.println(filterStr(list, (s) -> s.length() > 3));
}
}
其他函数式接口描述:https://www.runoob.com/java/java8-functional-interfaces.html
方法引用
方法引用比lambda表达式代码量更简洁
public static void main(String[] args) {
//lambda表达式的写法
Consumer<String> consumer = (str) -> System.out.println(str);
//方法引用的写法,使用两个英文冒号,后面跟方法名
//要求println方法的入参和返回值和Consumer接口的方法一直才能这样使用
Consumer<String> _consumer = System.out::println;
//其他示例
Supplier<Double> supplier = () -> Math.random();
Supplier<Double> _supplier = Math::random; //使用静态方法
//使用第一个参数的方法进行调用
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
BiPredicate<String, String> bp2 = String::equals;
System.out.println(bp.test("abcde", "abcde"));
//比较两个Employee类
BiPredicate<Employee, Employee> biPredicate = (e1,e2) -> e1.compare(e2);
//第一个入参是e1,返回值时使用e1.compare返回的,这种情况就可以简写为e1::xxx
BiPredicate<Employee, Employee> bp3 = Employee::compare;
System.out.println(bp3.test(new Employee("zhangsan"), new Employee("lisi")));
//构造方法引用
Supplier<Employee> supplier3 = Employee::new;
Employee employee = supplier3.get();
//有参构造方法引用
Function<String, Employee> function = Employee::new;
Employee employee2 = function.apply("wangwu");
//数组引用
Function<Integer, String[]> fun = (size) -> new String[size];
Function<Integer, Employee[]> fun2 = Employee[] :: new;
}
public class Employee {
private int id;
private String name;
private int age;
private double salary;
public Employee() { }
public Employee(String name) {
this.name = name;
}
public boolean compare(Employee employee){
return this.getName().equals(employee.getName());
}
}