写在前面
本文主要是简单介绍Lambda表达式和函数式接口的使用方法,并不涉及原理,希望初学者看完之后可以在日常开发中灵活运用Lambda表达式编程
Lambda的特性
Java 8 增加了一个全新语言级别的功能,称为 Lambda 表达式。允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理存储在变量中
Lambda表达式语法
Lambda表达式由参数列表和方法体组成:`(type1 arg1,type2 arg2,...) -> {body;};`参数之间用`,`分隔
- 1、没有入参时,用
( )
空括号表示。如:() -> {body};
-
2、入参只有一个时,可以有两种表示方式:
1) (String s) -> {body}; 2)s -> {body}; 省略了参数的类型,Lambda会根据上下文推断出参数类型,并且不需要括号包围
-
3、有多个入参时:
(String name,int age,boolean flag) -> {body}
也可以省略参数类型直接写成这样:`(name,age,flag) -> {body}` 参数列表必须有`()`包围
- 4、当方法体只有一条语句时,可以省略
{ }。如:() -> System.out.println("hello world");
- 一些例子:
1、()-> System.out.println("Lambda表达式");
2、(String s) -> System.out.println(s);
3、s -> return s;
4、(String s,int num) -> {
if(num >= 10){
return s.toUpperCase();
}
return s.toLowerCase();
};
5、(age,name,flag) -> 42;
Lambda表达式不能单独使用,需要绑定函数式接口才能使用
函数式接口
函数式接口(Functional Interface)是Java 8对一类特殊类型的接口的称呼。 这类接口抽象方法的数量只有一个,并且使用了@FunctionalInterface进行注解。需要注意的是,只有一个抽象方法的接口,即使没有@FunctionalInterface进行注解,编译器也会把它当作函数式接口。
特殊的是java.util.Comparator<T>接口具有两个抽象方法,如下:
int compare(T o1, T o2);
boolean equals(Object obj);
但它仍然是函数式接口,为什么呢?
如果接口声明了一个覆盖 java.lang.Object公共方法的抽象方法,那么这个方法不会计入接口的抽象方法计数中,因为该接口的任何实现都将具有来自java.lang.Object或其他地方的针对于该方法的实现。java.util.Comparator<T>接口中的equals(Object obj)方法是java.lang.Object中的一个public方法的声明,不在抽象方法的计数中
实际上Lambda表达式就是对函数式接口中唯一的抽象方法的实现,所以Lambda表达式的参数需要和函数式接口抽象方法的参数列表一致。
在jdk8中,引入了一个新的包java.util.function, 提供了一系列的函数式接口,这个包中的接口大致可以分为以下四类:
Function<T,R>: 接收参数,并返回结果,抽象方法为 R apply(T t)
Consumer<T>: 接收参数,无返回结果, 抽象方法为 void accept(T t)
Supplier<T>: 不接收参数,但返回结果,抽象方法为 T get()
Predicate<T>: 接收参数,返回boolean值,抽象方法为 boolean test(T t)
可以根据需要选择不同的函数式接口,不需要每次自定义函数式接口使用
Lambda表达式和函数式接口的实例应用
1、获得函数式接口的实例对象,进行方法的调用
//自定义函数式接口
@FunctionalInterface
public interface TestFunctionInterface {
//函数式接口的唯一抽象方法,需要Lambda表达式实现
String testFunction(String a,int b);
}
//测试类
public class Client {
public static void main(String[] args) {
//使用Lambda表达式实现TestFunctionInterface的抽象方法,并且得到实例对象
TestFunctionInterface testFunctionInterface = (String name,int age)->{
if(age==10){
return name.toUpperCase();
}
return "NO NAME!";
};
//通过testFunctionInterface调用testFunction()方法并传入参数,得到返回的结果result
String result = testFunctionInterface.testFunction("David",10);
System.out.println(result);
}
}
打印结果:DAVID
----------
2、函数式接口作为某个方法的参数使用
//自定义函数式接口
@FunctionalInterface
public interface TestFunctionInterface {
//函数式接口的唯一抽象方法,需要Lambda表达式实现
String testFunction(String a,int b);
}
//测试类
public class Client {
public static void main(String[] args) {
//调用test方法
test("steven",20,(name,age) -> {
if(age==10){
return name.toUpperCase();
}
return "NO NAME!";
}
);
}
//函数式接口对象作为参数的方法
public static void test(String name,int age,TestFunctionInterface testFunctionInterface){
String result = testFunctionInterface.testFunction(name,age);
System.out.println(result);
}
}
打印结果:NO NAME!
特别注意:以上两种方法使用Lambda表达式时,Lambda的参数和返回值必须要和函数式接口的抽象方法保持一致
方法引用
Lambda表达式使用::
来调用特定的已存在方法作为函数式接口唯一抽象方法的实现,可以使代码更具可读性
1.静态方法
Lambda :(arg0,arg1,arg2,...) -> ClassName.staticMethod(arg0,arg1,arg2,...)
方法引用:ClassName::staticMethod
`TestStaticMethod::testStaticMethod` 即调用`TestStaticMethod`的静态方法`String testStaticMethod(int age,boolean flag)`作为函数式接口抽象方法的实现,调用的方法的参数类型和返回值需要和抽象方法保持一致
@FunctionalInterface
public interface TestFunctionInterface {
String testFunction(int i);
}
public class TestStaticMethod {
public static String testStaticMethod(int age,boolean flag){
if(age >10 && flag){
return "SUCCESS";
}
return "ERROR";
}
}
public class Client {
public static void main(String[] args) {
//TestStaticMethod::testStaticMethod 相当于Lambda表达式:(int age,boolean flag) -> TestStaticMethod.testStaticMethod(age,flag);会将Lambda的参数按顺序传入调用的方法中,类型不匹配会报错
TestFunctionInterface testFunctionInterface = TestStaticMethod::testStaticMethod;
String result = testFunctionInterface.testFuction(26,true);
System.out.println(result);
}
}
打印结果:SUCCESS
2.指向任意类型的实例方法引用
Lambda:(arg0,arg1,arg2,...) -> arg0.instanceMethod(arg1,arg2,...)
方法引用:ClassName.instanceMethod(注意:arg0是ClassName类型的对象)
/**
1) 函数式接口抽象方法只有一个参数
*/
@FunctionalInterface
public interface TestFunctionInterface {
int testFuction(String s);
}
public class Client {
public static void main(String[] args) {
//方法引用:String::length 等价于 Lambda表达式:(arg0) -> arg0.length()
//实际上调用参数对象arg0的length()方法作为抽象方法的方法体实现,arg0.length()的返回值作为抽象方法的返回值
TestFunctionInterface testFunctionInterface = String::length;
System.out.println(testFunctionInterface.testFuction("king"));
}
}
打印结果:4
/**
2) 函数式接口抽象方法有多个参数
*/
@FunctionalInterface
public interface TestFunctionInterface {
int testFuction(TestMethodRef testMethodRef, String name, int age);
}
public class TestMethodRef {
public int testMethodRef(String name,int age){
return name.length()+age;
}
}
public class Client {
public static void main(String[] args) {
//TestMethodRef::testMethodRef 等价于 (arg0,arg1,arg2) -> arg0.testMethodRef(arg1,arg2)
//编译器只会调用第一个参数arg0的testMethodRef(arg1,arg2)方法,并且把余下的arg1,arg2按原来的顺序作为参数传入该方法中,类型不匹配会报错
TestFunctionInterface testFunctionInterface = TestMethodRef::testMethodRef;
int result = testFunctionInterface.testFuction(new TestMethodRef(),"king",12);
System.out.println(result);
}
}
打印结果:16
3.指向现有对象的实例方法引用
@FunctionalInterface
public interface TestFunctionInterface {
char testFuction(int index);
}
public class Client {
public static void main(String[] args) {
String content="hello";
//content::charAt 等价于 (int index) -> content.charAt(index);
TestFunctionInterface testFunctionInterface = content::charAt;
System.out.println(testFunctionInterface.testFuction(0));
}
}
打印结果:h
Stream API
java.util.stream.Stream接口 和 Lambda 表达式一样,都是 Java 8 新引入的。所有 Stream 的操作必须以 Lambda 表达式为参数。Stream(流)是一个来自数据源的元素队列并支持聚合操作,它将处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果,这里简单介绍一下常用的Stream API
- forEach 提供对stream流元素的迭代功能
public class Client {
public static void main(String[] args) {
List<Info> list = new ArrayList<>();
list.add(new Info("first", 1));
list.add(new Info("second", 2));
list.add(new Info("third", 3));
list.add(new Info("four", 4));
list.add(new Info("five", 5));
//list.stream()创建Stream流,调用forEach打印所有的name
list.stream().forEach(t->System.out.println(t.name));
}
}
打印结果:
first
second
third
four
five
- filter 设置过滤限制
public class Client {
public static void main(String[] args) {
List<Info> list = new ArrayList<>();
list.add(new Info("first", 1));
list.add(new Info("second", 2));
list.add(new Info("third", 3));
list.add(new Info("four", 4));
list.add(new Info("five", 5));
//针对age进行过滤
list.stream().filter(t->t.age>3).forEach(t->System.out.println(t.name));
}
}
打印结果:
four
five
- map 将流元素映射到不同的结果
public class Client {
public static void main(String[] args) {
List<Info> list = new ArrayList<>();
list.add(new Info("first", 1));
list.add(new Info("second", 2));
list.add(new Info("third", 3));
list.add(new Info("four", 4));
list.add(new Info("five", 5));
//将Info对象映射成String对象
List<String> names=list.stream().map(t->t.name).collect(Collectors.toList());
}
}
- limit 获取指定数量的流元素
Stream.of(1,2,3,4,5,6,7).limit(3).forEach(System.out::println);
打印结果:
1
2
3
- skip 忽略指定数量的流元素
//忽略前4个流元素
Stream.of(1,2,3,4,5,6,7).skip(4).forEach(System.out::println);
打印结果:
5
6
7
- sorted 对流进行排序
public class Client {
public static void main(String[] args) {
List<Info> list = new ArrayList<>();
list.add(new Info("first", 1));
list.add(new Info("second", 2));
list.add(new Info("third", 3));
list.add(new Info("four", 4));
list.add(new Info("five", 5));
list.stream().sorted(new Comparator<Info>() {
@Override
//根据age降序排列
public int compare(Info o1, Info o2) {
return o2.age-o1.age;
}
}).forEach(t->System.out.print(t.name+" "));
}
}
打印结果:five four third second first
- findFirst 返回第一个元素
//findFirst()返回Optional对象,需要调用Optional.get()方法获取值
int value=Stream.of(1,2,3,4,5,6,7).findFirst().get();
System.out.println(value);
打印结果:1
- anyMatch 匹配任意一个就返回true
//stream流中只要有一个元素的值等于2,就返回true
boolean value=Stream.of(1,2,3,4,5,6,7).anyMatch(t->t==2);
System.out.println(value);
打印结果:
true
- allMatch 匹配所有元素才返回true
//stream流中所有元素的值都等于2,才返回true
boolean value=Stream.of(1,2,3,4,5,6,7).allMatch(t->t==2);
System.out.println(value);
打印结果:
false
- collect 将Stream转换为集合
List list=Stream.of(1,2,3,4,5,6,7).collect(Collectors.toList());
Set set = Stream.of(1,2,3,4,5,6,7).collect(Collectors.toSet());
最后
希望大家在开发中可以多使用Lambda表达式、函数式接口和Stream API,真的很方便并且效率更高。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。