目录
lambda表达式
Lambda 允许把函数作为一个方法的参数
一切皆为函数,函数可以作为另一个函数的输入/输出,形成表达式链
使用 Lambda 表达式可以使代码变的更加简洁紧凑
推动 Java 8 发布的最重要新特性
【直观体验】
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
【Demo1】
/**
* @author: wangmingxin03
* @date: 2020-07-02
*/
public class Main {
public static void main(String[] args) throws Throwable {
Supplier<Integer> integerSupplier = () -> 5;
Integer i = integerSupplier.get();
System.out.println(i);
Weigher<Integer, Integer> kvWeigher = (x, y) -> x + y + 6;
int weigh = kvWeigher.weigh(1, 3);
System.out.println(weigh);
ThrowableConsumer<String, Throwable> stringThrowableThrowableConsumer =
(String x) -> System.out.println(x);
stringThrowableThrowableConsumer.accept("xinye");
}
}
【Demo2】
/**
* @author: wangmingxin03
* @date: 2020-07-02
*/
public class Main {
public static void main(String[] args) {
Plus plus = (x,y) -> x+y;
int add = plus.plus(1, 2);
System.out.println(add);
}
}
@FunctionalInterface
interface Plus {
int plus(int x,int y);
}
【Demo3】
/**
* @author: wangmingxin03
* @date: 2020-07-03
*/
public class Test3 {
public static void main(String[] args) {
int num = 1;
Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2);
}
}
interface Converter<T1, T2> {
void convert(int i);
}
输出3 没什么问题
我们如果在下面对num
重新赋值呢?
在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量
Lambda方法引用
方法引用可以看作仅仅调用特定方法方法的 lambda 的一种快捷的方式
public void functionRef() {
Apple one = new Apple(20);
Apple two = new Apple(10);
List<Apple> appleList = Arrays.asList(one, two);
appleList.sort((a1, a2)->a1.getWeight().compareTo(a2.getWeight()));
appleList.sort(Comparator.comparing(Apple::getWeight));
}
Apple::getWeight
就是方法引用
lambda 内置函数
【接口java.util.function.Predicate】
核心方法
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
//过滤大于等于20岁的人
Predicate<Integer> agePredicate = (age) -> age >= 20;
List<Person> oldPeople = people.stream()
.filter(person -> agePredicate.test(person.getAge()))
.collect(Collectors.toList());
System.out.println(oldPeople);
输出: [Person{name=’张三’, age=20}, Person{name=’李四’, age=21}]
【接口java.util.function.Supplier】
提供者
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
Supplier<Person> getInstance = () -> new Person("xx", 18);
System.out.println(getInstance.get());
输出: Person{name=’xx’, age=18}
【接口java.util.function.Consumer】
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
Consumer 消费
accept
接受一个参数做处理
Consumer<Person> personConsumer =
(Person p) -> System.out.println("幸运儿 " + p.getName());
personConsumer.accept(p1);
输出: 幸运儿 张三
【接口java.util.function.Function】
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
给一个类型的对象转为另一个灵性的对象,这个是我们最常用的
Function<Person, String> nickNameFunction =
(Person p) -> p.getName() + "_帅气";
List<String> nickNameList =
people.stream().map(nickNameFunction).collect(Collectors.toList());
System.out.println(nickNameList);
输出: [张三帅气, 李四帅气, 王五_帅气]
Stream的定义与理解
A sequence of elements supporting sequential and parallel aggregate operations.
1. Stream是元素的集合,这点让Stream看起来用些类似Iterator
2. 可以支持顺序和并行的对原Stream进行汇聚的操作
Stream类图
Stream的基本步骤
- 创建Stream 一个数据源 如集合
- 转换Stream(可以有多次转换) 中间操作链
- 对Stream进行聚合 终端操作
构建流
- 由值创建流
Stream<Integer> integerStream = Stream.of(1,2,3,5);
integerStream.forEach(e->System.out.println(e));
- 由数组创建流
int []nums = {};
Arrays.stream(nums)
- 由文件生成流
Files.lines
- 由函数生成流
无限流(没有固定大小的流)
Stream.iterate()
Stream.generate()
无限流一般需要limit来显示限定大小
Stream.iterate(0, n -> n + 2)
.limit(10)
.forEach(System.out::println);
Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);
转换Stream
转换Stream其实就是把一个Stream通过某些行为转换成一个新的Stream
【filter】
过滤
【map】
映射
【limit】
对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素;
【skip】
返回一个丢弃原Stream的前N个元素后剩下元素组成的新Stream,如果原Stream中包含的元素个数小于N,那么返回空Stream;
最常用的就是filter、map了
原始类型流特化
解决装箱造成的复杂性
IntStream
LongStream
package pers.wmx.springbootfreemarkerdemo.java8;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
/**
* @author: wangmingxin03
* @date: 2020-07-03
*/
public class Test4 {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
Person p1 = new Person();
p1.setName("张三");
p1.setAge(20);
Person p2 = new Person();
p2.setName("李四");
p2.setAge(21);
Person p3 = new Person();
p3.setName("王五");
p3.setAge(18);
people.add(p1);
people.add(p2);
people.add(p3);
IntStream ageStream = people.stream().mapToInt(Person::getAge);
//求合
System.out.println(ageStream.sum());
}
}
class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
输出: 59
IntStream ageStream = people.stream().mapToInt(Person::getAge);
//求合
System.out.println(ageStream.sum());
//再次求合
System.out.println(ageStream.sum());
我们基于得到的流再求一次合
运行报异常
Exception in thread “main” java.lang.IllegalStateException: stream has already been operated upon or closed
说明流不能被重复使用
如果还想如用,需再从原集合获取流
获取最大值和最小值
int maxAge = people.stream()
.mapToInt(Person::getAge).max().orElse(0);
System.out.println(maxAge);
int minAge = people.stream()
.mapToInt(Person::getAge).min().orElse(0);
System.out.println(minAge);
流的扁平化
flatMap
//又来了一批年龄大的people list
List<Person> people1 = new ArrayList<>();
Person p4 = new Person();
p1.setName("赵六");
p1.setAge(40);
Person p5 = new Person();
p2.setName("王二麻子");
p2.setAge(99);
Person p6 = new Person();
p3.setName("赵二瘸子");
p3.setAge(200);
people1.add(p4);
people1.add(p5);
people1.add(p6);
List<List<Person>> personList = new ArrayList<>();
personList.add(people);
personList.add(people1);
//想把这两个list合成一个
List<Person> finalPersonList = personList.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println(finalPersonList);
输出:
[Person{name=’张三’, age=20}, Person{name=’李四’, age=21}, Person{name=’王五’, age=18}, Person{name=’赵六’, age=40}, Person{name=’王二麻子’, age=99}, Person{name=’赵二瘸子’, age=200}]
flatMap 方法让你把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流。
查找与匹配
也称短路操作
allMatch anyMatch noneMatch findFirst findAny
较简单,通常用来查找符合条件的元素
比如 anyMatch 流中是否有一个元素能匹配给定的谓词
//是否有(存在)大于100岁的
boolean flag = finalPersonList.stream()
.anyMatch(person -> person.getAge() > 100);
System.out.println(flag);
输出: true
用流收集数据
用流收集数据
前面已经用过了
.collect(Collectors.toList());
把一系列的中间操作聚合,即终端操作会消耗流
上面有个例子有体现,流是不能重复使用的
其实所有的收集器都来自于 Collectors.reducing
其他的用法都是衍生出来的,更加方便我们使用流
//求流中的元素个数
long peopleCount1= finalPersonList.stream().collect(Collectors.counting());
long peopleCount2= finalPersonList.stream().count();
System.out.println(peopleCount1);
System.out.println(peopleCount2);
最后再简单介绍一个分组,也是我们经常用的
//按年龄分组
Map<Boolean, List<Person>> personMap =
finalPersonList.stream().collect(Collectors.groupingBy(p -> p.getAge() > 50));
List<Person> oldPersonList = personMap.get(true);
List<Person> youngPersonList = personMap.get(false);
System.out.println(youngPersonList);
System.out.println(oldPersonList);
输出:
[Person{name=’张三’, age=20}, Person{name=’李四’, age=21}, Person{name=’王五’, age=18}, Person{name=’赵六’, age=40}]
[Person{name=’王二麻子’, age=99}, Person{name=’赵二瘸子’, age=200}]
我们还可以根据对象的某一属性来进行分组,比如Person再加一个属性爱好,
根据爱好来分成多组
转载请注明:汪明鑫的个人博客 » Lambda & Stream 使用入门详解
说点什么
您将是第一位评论人!