1 lambda表达式
lambda表达式是一个可传递的代码块,可以在以后一次或多次执行,它采用了一种简洁的方式来定义代码块
lambda表达式类似于方法,可以将其理解成匿名函数,它可以有参数和返回值
Lambda表达式可以作为方法的参数
1.1 基本语法
(参数1, 参数2...) -> { 代码块 }
如果没有参数,直接写为:()->
如果只有一个参数,一个语句,可以简写为:参数 -> 语句
interface MyInter1 {
void show();
}
interface MyInter2 {
void show(int a);
}
interface MyInter3 {
int add(int a, int b);
}
public class LambdaTest2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 无参无返回值
MyInter1 myInter = () -> {
System.out.println("haha");
};
myInter.show();
// 有参无返回值
MyInter2 myInter2 = (int a) -> {
System.out.println(a);
};
myInter2.show(30);
// 类型可以省略
MyInter2 myInter22 = (a) -> {
System.out.println(a);
};
myInter22.show(30);
// 如果只有一个参数,语句块只有一条语句,参数的括号和语句块的大括号可以省略
MyInter2 myInter222 = a -> System.out.println(a);
myInter222.show(40);
// 有参有返回值
MyInter3 myInter3 = (a, b) -> {return a + b;};
int sum = myInter3.add(12, 20);
System.out.println(sum);
// 只有一条return语句, return可以省略,大括号可以省略
MyInter3 myInter33 = (a, b) -> a + b;
sum = myInter33.add(15, 20);
System.out.println(sum);
}
}
1.2 lambda表达式作为参数使用
interface CallInterface {
void call(String info);
}
public class LambdaTest3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
test((info) -> {
System.out.println(info);
});
}
public static void test(CallInterface callInterface) {
callInterface.call("hahahaha");
}
}
1.3 jdk中使用lambda例子
List<Integer> list = new ArrayList<Integer>();
list.add(12);
list.add(23);
list.add(5);
list.forEach((n) -> {System.out.println(n);});
// 可以简写为
list.forEach(n -> System.out.println(n));
// 多线程
Thread thread = new Thread(() -> {
for(int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread() + ":" + i);
}
});
thread.start();
// 排序
Integer[] ints = {98, 243, 35, 13, 57, 243};
List<Integer> list = Arrays.asList(ints);
Collections.sort(list2, (o1,o2) -> o1 - o2);
Collections.sort(list2, (o1,o2) -> {return o1 - o2;});
2 Stream
Stream流是 JDK8中新增的一个处理集合的关键抽象概念。
2.1 生成Stream对象
Java中提供了多种方法生成流对象,通过集合生成Stream对象是最常用的方式。
JDK8中,集合新增了两个流方法,分别是 stream() 和 parallelStream(),通过该方法可以获取Stream对象。比如:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = list.stream();
2.2 Stream的操作
流的操作类型主要分为两种
1)中间操作 :其目的主要是打开流,做出某种操作后,返回一个新的流,然后交给下一个操作使用。这类操作都是惰性化的,仅仅调用到这类方法,并没有真正开始流的遍历,真正的遍历需等到终端操作时进行。
2)结束操作: 一个流有且只能有一个结束操作,当这个操作执行后,流就被关闭了。
中间操作 | 无状态 | unordered、filter、map、mapToInt、mapToLong、mapToDouble、flatMap、flatMapToInt、flatMapToLong、flatMapToDouble、peek |
---|---|---|
有状态 | distinct、sorted、limit、skip | |
结束操作 | 非短路操作 | forEach、forEachOrdered、toArray、collect、max、min、count、reduce |
短路操作 | anyMatch、allMatch、noneMatch、findFirst、findAny |
无状态:指元素的处理不受之前元素的影响;
有状态:指该操作只有拿到所有元素之后才能继续下去。
非短路操作:指必须处理所有元素才能得到最终结果;
短路操作:指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要A为true,则无需判断B的结果。
2.2.1 中间操作
1)filter筛选
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = integerList.stream().filter(i -> i > 3);
// 为了方便演示,转为集合类型
List<Integer> collect = integerList.stream().filter(i -> i > 3).collect(Collectors.toList());
System.out.println(collect);
2)distinct去除重复元素
List<Integer> integerList = Arrays.asList(1, 1, 2, 2, 3, 4, 4, 5);
Stream<Integer> stream = integerList.stream().distinct();
3)limit返回指定流个数
取指定个数的数据
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = integerList.stream().limit(3);
4)map流映射
所谓流映射就是将接受的元素映射成另外一个元素
List<String> stringList = Arrays.asList("zhangsan", "lisi", "wangwu", "haha");
Stream<Integer> stream = stringList.stream().map(item -> item.length());
5)flatMap流转换
将一个流中的每个值都转换为另一个流
List<String> list = Arrays.asList("I love you", "I hate you");
List<String> strList = list.stream()
.map(item -> item.split(" "))
.flatMap(item -> Arrays.stream(item))
.collect(Collectors.toList());
2.2.2 结束操作
1)统计流中元素个数
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Long result = integerList.stream().count();
2)findFirst查找第一个元素
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result = integerList.stream().filter(i -> i > 3).findFirst();
// orElse() 值存在就返回,不存在,返回执行值,比如null
Integer value = integerList.stream().filter(i -> i > 3).findFirst().orElse(null);
3)返回集合
List<Integer> collect = integerList.stream().filter(i -> i > 3).collect(Collectors.toList());
4)通过groupingBy进行分组
Map<String, List<Employee>> collect = list.stream().collect(Collectors.groupingBy(Employee::getSex));
5)reduce将流中的元素组合起来
假设我们对一个集合中的值进行求和
// 第一个参数是初始值,第二个参数是元素结合起来的算法
int sum = integerList.stream().reduce(0, (a, b) -> (a + b));
3 ::语法 了解
方法引用,方法引用通过一对双冒号:: 来表示,方法引用相当于对特定写法的lambda表达式的简化,是函数式接口的另一种书写方式。
lambda表达式可用方法引用代替的场景:
lambda表达式的代码块中包含一条语句,且该语句仅调用一个已经存在的方法
规则:
通用规则:引用的方法的返回值和参数,与函数式接口中方法和参数一致
针对实例方法引用:lambda表达式的第一个入参为实例方法的调用者,后面的入参与实例方法的入参一致
引用方式:
静态方法引用:
类名::静态方法名, 如 Integer::parseInt
实例方法引用:
对象名::实例方法,如 str::substring
类名::实例方法,如 Employee::getAge
构造方法引用:
类名::new, 如 User::new
附录
Java中的函数式接口
函数式接口的定义是: 只包含一个抽象方法的接口,称为函数式接口;
其实我们的Lambda表达式就是对函数式接口的一种简写方式,所以只有是函数式接口,我们才能用Lambda表达式;再换句话说,Lambda表达式需要函数式接口的支持,函数式接口我们可以自己定义,JDK也给我们提供了一些现成的函数式接口。