声明:本文章内容主要摘选自尚硅谷宋红康Java教程、《Java核心卷一》、廖雪峰Java教程,示例代码部分出自本人,更多详细内容推荐直接观看以上教程及书籍,若有错误之处请指出,欢迎交流。
Lambda表达式与方法引用
一、Lambda表达式
在我们之前学过的一些方法如equals(),compare()都是将一个代码块传递给某个对象,但在Java中不能直接传递代码段,必须构造一个对象,这个对象必须有一个类的方法来所需的代码。而我们这种直接传递代码块的做法包含函数式编程(Functional Programming),把函数作为基本运算单元,函数可以作为变量,可以接收函数,还可以返回函数。历史上研究函数式编程的理论是Lambda演算,所以我们经常把支持函数式编程的编码风格称为Lambda表达式
。
1.举例:(o1,02)->Integer.compare(o1,o2);
2.格式:
一>:Lambda操作符或箭头操作符
一>的左边:Lambda形参列表(其实就是接口中的抽象方法的参数列表)
一>的右边:Lambda体(其实就是重写的抽象方法的方法体)
3.Lambda表达式的使用:(分为4种情况介绍)
public class LambdaTest {
@Test
public void test1(){
//语法格式一:无参,无返回值
//使用Lambda表达式之前的写法
Runnable r1 = new Runnable(){
public void run(){
Runnable r2 = () -> System.out.println("我爱小姐姐");
}
};
r1.run();
System.out.println("*******************************");
//使用Lambda表达式
Runnable r2 = () -> {
System.out.println("我爱小姐姐");
};
r2.run();
//语法格式二:Lambda 需要一个参数,但无返回值
Consumer<String> con1 = new Consumer<>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con1.accept("请问你要喝点什么?");
Consumer<String> con2 = (String s) ->{ //可写为s,因为会自动推断类型,且小括号可以省略
System.out.println(s);
}; //即Consumer<String> con2 = System.out::println;
con2.accept("抹茶拿铁,谢谢。");
}
@Test
public void test2(){
//语法格式三:Lambda 需要两个及以上参数,多条运行语句,并可以有返回值
Comparator<Integer> c1 = (o1, o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
System.out.println(c1.compare(199, 23));
}
@Test
public void test3(){
//语法格式四:当Lambda只有一条语句时,大括号与return若有,都可以忽略
Comparator<Integer> c1 = (o1, o2) -> {
return o1.compareTo(o2);
};
System.out.println(c1.compare(19, 23));
System.out.println("************************");
Comparator<Integer> c2 = (o1, o2) -> o1.compareTo(o2);
System.out.println(c2.compare(92, 23));
}
}
4.Lambda的实质:作为函数式接口的实例
5.如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口
。
我们可以在一个接口上使用@Functional Interface 注解,这样做可以检查它是否是一个函数式接口。
6.所有以前用匿名实现类表示的现在都可以用Lambda表达式来写。
常用函数式接口
函数式接口 | 参数类型 | 返回类型 | 抽象方法名 | 描述 |
---|---|---|---|---|
Runnable | 无 | void | run | 作为无参数或返回值的动作运行 |
Supplier |
无 | T | get | 提供一个T类型的值 |
Consumer |
T | void | accept | 处理一个T类型的值 |
BiConsumer<T,U> | T,U | void | accept | 处理T和U类型的值 |
Function<T,R> | T | R | apply | 有一个T类型参数的函数 |
BiFunction<T,U,R> | T,U | R | apply | 有T和U类型参数的函数 |
UnaryOperator |
T | T | apply | 类型T上的一元操作符 |
BinaryOperator |
T,T | T | apply | 类型T上的二元操作符 |
Predicate |
T | boolean | test | 布尔值函数 |
BiPredicate<T,U> | T,U | boolean | test | 有两个参数的布尔值函数 |
二、方法引用
1.使用情境:当要传遵给Lambda体的操作,T已经有实现的方法了,可以使用方法引用!
2.方法引用,本师上就是Lambda表达式,而Lambda表达式作为函或式接口的实例。所以方法引用,也是函数式接口的实例。
3.使用格式:类(或对象)::方法名
4.具体分为如下的三种情况:
-
对象::非静态方法
-
类::静态方法
-
类::非静态方法
5.方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!
public class MethodRefTest { @Test public void test1(){ //情况一:对象 :: 实例方法 //Consumer<T> void accept(T t) Consumer<String> c1 = str -> System.out.println(str); c1.accept("这是Lambda表达式的写法"); System.out.println("*********************"); PrintStream ps = System.out; Consumer<String> c2 = ps::println; c2.accept("这是方法引用的写法"); //Supplier<T> T get() Person p = new Person("晓潇", 19, 5000); Supplier<String> sup = p::toString; sup.get(); } //情况二: 类 :: 静态方法 //Comparator 中的int compare(T t1,T t2) //Integer 中的int compare(T t1,T t2) @Test public void test2(){ Comparator<Integer> c1 = (o1, o2) -> Integer.compare(o1, o2); System.out.println(c1.compare(23, 91)); System.out.println("******************"); Comparator<Integer> c2 = Integer::compare; System.out.println(c2.compare(45, 34)); } //Function 中的R apply(T t) //Math 中的long round(Double d):四舍五入 @Test public void test3(){ Function<Double, Long> f1 = d -> Math.round(d); System.out.println(f1.apply(3.2)); System.out.println("******************"); Function<Double, Long> f2 = Math::round; System.out.println(f2.apply(8.9)); } //情况三:类::实例方法 //Comparator 中的int compare(T t1,T t2) //String中的int t1.compareTo(t2) @Test public void test4(){ Comparator<String> c1 = (s1, s2) -> s1.compareTo(s2); System.out.println(c1.compare("abc","abd")); System.out.println("***************************"); Comparator<String> c2 = String::compareTo; System.out.println(c2.compare("e", "a")); } //Function中的R appLy(T t) //Employee 中的string getName(); @Test public void test5(){ Person p = new Person("晓潇", 19, 5000); Function<Person, String> fun = Person::getName; System.out.println(fun.apply(p)); } /* * 【构造器引用】 和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。 抽象方法的返回值类型即为构造器所属的类的类型 * */ @Test public void test6(){ BiFunction<String, Integer, Person> fun = Person::new; System.out.println(fun.apply("晓潇", 19)); } /* * 【数组引用】 大家可以把数组看做是一个特殊的类,则写法与构造器引用一致。 * */ @Test public void test7(){ Function<Integer, String[]> fun = String[]::new; String[] str = fun.apply(10); System.out.println(Arrays.toString(str)); } }
此笔记仅针对有一定编程基础的同学,且本人只记录比较重要的知识点,若想要入门Java可以先行观看相关教程或书籍后再阅读此笔记。
最后附一下相关链接:
Java在线API中文手册
Java platform se8下载
尚硅谷Java教学视频
《Java核心卷一》