前言:为什么使用lambda表达式
Lambda是一个匿名函数,我们可以把
Lambda
表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使
Java
的语言表达能力得到了提升。
一、Lambda表达式语法
Lambda表达式在Java语言中引入了一个新的语法元素和操作符。这个操作符为“->”,该操作符被称为Lambda操作符或剪刀操作符。
它将Lambda分为两个部分:
左侧:
指定了Lambda表达式需要的所有参数
右侧:
指定了Lambda体,即Lambda表达式要执行的功能。
语法格式一:
无参,无返回值,Lambda体只需要一条语句
/*
语法格式一:无参,无返回值,Lambda体只需要一条语句
*/
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
Runnable runnable1 = () -> System.out.println("Hello Lambda");
runnable.run();
runnable1.run();
语法格式二:Lambda 需要一个参数
Consumer<String> fun = (e) -> System.out.println(e);
fun.accept("Hello lambda");
语法格式三:
Lambda只需要一个参数时,参数的小括号可以省略
Consumer<String> fun = e -> System.out.println(e);
fun.accept("Hello lambda");
语法格式四:Lambda需要两个参数,并且有返回值
Comparator<Integer> comparator = (x,y) -> {
System.out.println("函数式接口");
return Integer.compare(x,y);
};
int result = comparator.compare(10,2);
System.out.println(result);
/*
非lambda表达式
*/
Comparator<Integer> comparator1 = new Comparator<Integer>() {
@Override
public int compare(Integer x, Integer y) {
System.out.println("函数式接口");
return Integer.compare(x,y);
}
};
语法格式五:当Lambda体只有一条语句时,return与大括号可以省略
Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);;
int result = comparator.compare(10,2);
System.out.println(result);
语法格式六:
数据类型可以省略,因为可由编译器推断得出,称为“类型推断”.通常省略数据类型!
Comparator<Integer> comparator = (Integer x,Integer y) -> Integer.compare(x,y);
注:类型推断
上述Lambda 表达式中的参数类型都是由编译器推断得出的。Lambda 表达式中无需指定类型,程序依然可以编译,这是因为javac根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断”。
二、函数式接口
什么是函数式接口?
只包含一个抽象方法的接口,称为函数式接口。
你可以通过Lambda 表达式来创建该接口的对象。(若Lambda 表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。
我们可以在任意函数式接口上使用
@FunctionalInterface
注解,这样做可以检查它是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。
自定义函数式接口
不使用泛型
@FunctionalInterface
public interface MyNumber {
public double getValue();
}
使用泛型的函数式接口
@FunctionalInterface
public interface MyNumber<T> {
public double getValue(T t);
}
作为参数传递Lambda表达式
作为参数传递Lambda表达式:为了将Lambda表达式作为参数传递,接收Lambda表达式的参数类型必须是与该Lambda表达式兼容的函数式接口的类型。
Java内置四大核心函数式接口
//Predicate<T> 断言型接口:
@Test
public void test4(){
List<String> list = Arrays.asList("Hello", "atguigu", "Lambda", "www", "ok");
List<String> strList = filterStr(list, (s) -> s.length() > 3);
for (String str : strList) {
System.out.println(str);
}
}
//需求:将满足条件的字符串,放入集合中
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> strList = new ArrayList<>();
for (String str : list) {
if(pre.test(str)){
strList.add(str);
}
}
return strList;
}
//Function<T, R> 函数型接口:
@Test
public void test3(){
String newStr = strHandler("\t\t\t 我大尚硅谷威武 ", (str) -> str.trim());
System.out.println(newStr);
String subStr = strHandler("我大尚硅谷威武", (str) -> str.substring(2, 5));
System.out.println(subStr);
}
//需求:用于处理字符串
public String strHandler(String str, Function<String, String> fun){
return fun.apply(str);
}
//Supplier<T> 供给型接口 :
@Test
public void test2(){
List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));
for (Integer num : numList) {
System.out.println(num);
}
}
//需求:产生指定个数的整数,并放入集合中
public List<Integer> getNumList(int num, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = sup.get();
list.add(n);
}
return list;
}
//Consumer<T> 消费型接口 :
@Test
public void test1(){
happy(10000, (m) -> System.out.println("你们刚哥喜欢大宝剑,每次消费:" + m + "元"));
}
public void happy(double money, Consumer<Double> con){
con.accept(money);
}
其他接口
三、方法引用
当要传递给Lambda体的操作,已经有实现的方法了,就可以使用方法引用!(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致,以及返回值也需要一样!)
方法引用使用操作符
::
将方法名和对象或类的名字分割开来。
方式一:对象::实例方法
//对象的引用::实例的方法名
@Test
public void
test
()
{
Employee
employee
=
new
Employee
(
101
,
"zhouying"
)
;
Supplier
<
String
>
supplier
=
()
->
employee
.
getName
()
;
System
.
out
.
println
(
supplier
.
get
())
;
System
.
out
.
println
(
"------------------------------------"
)
;
Supplier
<
String
>
supplier1
=
employee::getName
;
System
.
out
.
println
(
supplier1
.
get
())
;
}
@Test
public void
test1
()
{
PrintStream
printStream
=
System
.
out
;
Consumer
<
String
>
consumer
=
(
x
)
->
printStream
.
println
(
x
)
;
consumer
.
accept
(
"Hello zy!"
)
;
System
.
out
.
println
(
"------------------------------------"
)
;
Consumer
<
String
>
consumer1
=
printStream::println
;
consumer1
.
accept
(
"Hello Java8"
)
;
System
.
out
.
println
(
"------------------------------------"
)
;
Consumer
<
String
>
consumer2
=
System
.
out
::println
;
consumer2
.
accept
(
"Hello "
)
;
方式二:类::静态方法
//类名::静态方法名
@Test
public void
test2
()
{
Comparator
<
Integer
>
comparator
=
(
x
,
y
)
->
Integer
.
compare
(
x
,
y
)
;
int
result
=
comparator
.
compare
(
1
,
2
)
;
System
.
out
.
println
(
result
)
;
System
.
out
.
println
(
"-----------------------------------"
)
;
Comparator
<
Integer
>
comparator1
=
Integer
::compare
;
int
result2
=
comparator1
.
compare
(
10
,
9
)
;
System
.
out
.
println
(
result2
)
;
}
@Test
public void
test3
()
{
BiFunction
<
Double
,
Double
,
Double
>
function
=
(
x
,
y
)
->
Math
.
max
(
x
,
y
)
;
System
.
out
.
println
(
function
.
apply
(
1.5
,
22.2
))
;
System
.
out
.
println
(
"----------------------------------------"
)
;
BiFunction
<
Double
,
Double
,
Double
>
function1
=
Math
::max
;
System
.
out
.
println
(
function1
.
apply
(
1.2
,
1.5
))
;
}
方式三:类::实例方法
/
/类名::实例方法名
@Test
public void
test4
()
{
BiPredicate
<
String
,
String
>
biPredicate
=
(
x
,
y
)
-> x
.
equals
(
y
)
;
System.out.println(biPredicate.test("abccde","abccde"));
System.out.println("------------------------------------------");
BiPredicate
<
String
,
String
>
biPredicate1
=
String
::equals
;
System.out.println(biPredicate1.test("a","a"));
System.out.println("------------------------------------------");
Function
<
Employee
,
String
>
function
=
(
e
)
-> e
.
toString
()
;
System
.
out
.
println
(
function
.
apply
(
new
Employee
()))
;
System.out.println("------------------------------------------");
Function
<
Employee
,
String
>
function1
=
Employee
::toString
;
System
.
out
.
println
(
function1
.
apply
(
new
Employee
()))
;
}
四、构造器引用
构造器的参数列表,需要与函数式接口中参数列表保持一致
方式一:类名::new
//构造器引用
@Test
public void
test6
()
{
Supplier
<
Employee
>
supplier
=
()
->
new
Employee
()
;
System.out.println(supplier.get());
System.out.println("---------------------------------");
Supplier
<
Employee
>
supplier1
=
Employee
::
new
;
System.out.println(supplier1.get());
System.out.println("---------------------------------");
Function
<
String
,
Employee
>
function
=
(
x
)
->
new
Employee
(
x
)
;
Employee
employee
=
function
.
apply
(
"zy"
)
;
System.out.println(employee);
Function
<
String
,
Employee
>
function1
=
Employee
::
new
;
Employee
employee1
=
function1
.
apply
(
"yz"
)
;
System.out.println(employee1);
}
输出如下:
Employee{id=null, name='null'}
---------------------------------
Employee{id=null, name='null'}
---------------------------------
Employee{id=null, name='zy'}
Employee{id=null, name='yz'}
五、数组引用
方式一:类型[]::new
//数组引用
@Test
public void
test10
()
{
Function
<
Integer
,
Employee
[]
>
function
=
Employee
[]
::
new
;
Employee
[]
employees
=
function
.
apply
(
10
)
;
System.out.println(employees.length);
}