文章目录
Lambda和Stream流
一、Lambda表达式
1、函数式接口
介绍Lambda之前,首先介绍一下函数式接口,函数式接口是Lambda和方法引用使用的前提。
格式:
@FunctionalInterface
interface 接口名 {
void 方法名();
}
值得注意的是:
1.函数式接口中只可以定义一个缺省属性是 public abstract 的尚未实现的方法。
2. Lambda表达式只在JDK1.8及以上版本可以使用
3. @FunctionalInterface为开启函数式接口严格检查,如果定义错误,编译器立马就会报错,但是如果本身就是函数式接口,那么不写也仍然是函数式接口。
2.Lambda表达式
2.1基本格式
对于Lambda表达式我们只需要关注函数式接口中未实现方法的参数和返回值。
基本格式:
() -> {}
() 中是联想的参数临时变量
-> 固定格式
{} 执行任务的代码块
2.2 Lambda演示
根据返回值和参数的不同,又可以将Lamdba分为四种
有参数有返回值
有参数无返回值
无参数有返回值
无参数无返回值
JDK1.8自带很多函数式接口,接下来用那些来举例。
2.2.1有参数有返回值Lambda
有参数有返回值的接口在开发中很常用,并且泛型也使得接口的使用更加自由,随心所欲,接下来用类型转换函数式接口来进行代码演示。
过滤器接口,判断接口,条件接口
@FunctionalInterface
public interface Predicate<T> {
/**
* 过滤器接口约束的方法,方法参数是用户使用时约束泛型对应具体数据参数
* 返回值类型是 boolean 类型,用于条件判断,数据过来
*
* @param t 用户约束泛型对应的具体数据类型参数
* @return boolean 数据,判断结果反馈
*/
boolean test(T t);
}
比较器接口
@FunctionalInterface
interface Comparator<T> {
/**
* 比较器接口要求的方法,参数是泛型参数,用户指定类型
*
* @param o1 用户在使用接口时约束的泛型对应具体数据类型参数
* @param o2 用户在使用接口时约束的泛型对应具体数据类型参数
* @return 返回值为 int 类型,0 表示两个元素一致。
*/
int compare(T o1, T o2);
}
类型转换器接口
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
方法设计
/**
* 将String类型字符串进行类型转换
*
* @param str 用户传入的字符串
* @param fun 类型转换器
* @return 返回转换的类型数据
*/
public static int testLambda(String str, Function<String, Integer> fun) {
return fun.apply(str);
}
类型转换接口代码实现
public static void main(String[] args) {
String str = "这里是类型转换接口";
//当参数只有一个可以省略小括号,当代码实现只有一行可以同时省略return 和大括号
int i = testLambda(str, s -> s.length());
System.out.println(i);
}
/**
* 将String类型字符串进行类型转换
*
* @param str 用户传入的字符串
* @param fun 类型转换器
* @return 返回转换的类型数据
*/
public static int testLambda(String str, Function<String, Integer> fun) {
return fun.apply(str);
}
值得一提的是:
当参数只有一个可以省略小括号,当代码实现只有一行可以同时省略return 和大括号
2.2.2 有参数无返回值Lambda
这种接口一般被称为消费者接口,用户传入参数,然后参数在接口内部自己消化掉了
接口展示:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
方法设计
/**
* 消费性接口()
* @param consumer 消费的规则
* @param money 消费的数据
*/
public static void play(Consumer<Integer> consumer,Integer money) {
consumer.accept(money);
}
这个方法设计比较简单,用户传入数据,然后被方法消费了。
消费者接口代码实现
public static void main(String[] args) {
/**
* 消费型:Consumer<T>
* 使用数据,对类型为T的对象进行操作
*/
//Lambda
play(money -> System.out.println("一条龙花费:" + money), 666);
//Lambda
play(System.out::println, 666);
}
/**
* 消费性接口()
* @param consumer 消费的规则
* @param money 消费的数据
*/
public static void play(Consumer<Integer> consumer,Integer money) {
consumer.accept(money);
}
2.2.3无参数有返回值Lambda
生产者接口,使用的数据都是对应方法的数据。
@FunctionalInterface
interface Supplier<T> {
/**
* 无参数有返回值方法,泛型约束的是接口对应的返回值数据类型,要求
* 按照泛型约束返回对应的数据内容
*
* @return 返回一个数据,符合泛型约束
*/
T get();
}
方法设计
/**
* 生成随机数组
* @param supplier 供给型接口,在这里提供随机数
* @param count 随机数的数量
* @return
*/
public static int[] getArr(Supplier<Integer> supplier,int count) {
//创建数组
int[] arr = new int[count];
//添加数据
for (int i = 0; i < arr.length; i++) {
//添加数据
arr[i] = supplier.get();
}
return arr;
}
这里设计了生成随机数据的方法,其中的数据内容可以自定义。
生产者接口代码演示:
public static void main(String[] args) {
/**
* 供给型接口Supplier<T>
* 返回类型为T的对象
*/
int[] arr = getArr(() -> new Random().nextInt(55) + 33, 10);
System.out.println(Arrays.toString(arr));
}
/**
* 生成随机数组
* @param supplier 供给型接口,在这里提供随机数
* @param count 随机数的数量
* @return 返回一个int类型数组
*/
public static int[] getArr(Supplier<Integer> supplier,int count) {
//创建数组
int[] arr = new int[count];
//添加数据
for (int i = 0; i < arr.length; i++) {
//添加数据
arr[i] = supplier.get();
}
return arr;
}
2.2.4无参数无返回值Lambda
这种接口一般没什么用处,因为不需要传入参数,也没有返回值要获得。
二、Stream流
1.概述
首先需要明确的是,Stream流是在1.8版本及以上支持的。
1.stream的功能:
stream流可以对数据进行筛选,去重,按照规则排序,限制个数,跳过指定个数,最终处理等等,并且stream在对数据进行操作的时候不会对原始数据进行修改。
2.stream流的获取:
- collection集合stream()方法
- Arrays的stream方法
2.Stream流相关方法
stream流操作的是集合或者数组,以下方法可以获取stream流对象。
// 集合对象
Stream<T> stream();
集合对象调用可以直接获取对应当前集合存储元素的 Stream 流对象。
// 数组
Stream<T> Arrays.Stream(T[] t);
利用 Arrays 工具类对当前需要按照 Stream 流方式操作的数据进行转换操作,根据当前数组的数据类型和数据存储情况,返回一个对应的 Stream 流对象
我们可以对stream流对象进行许多中间操作,例如:skip跳过,limit限制个数,sorted排序,filter过滤,distinct去重,map类型转换。,方法的详细解释如下:
Stream<T> skip(long n);
限制跳过当前 Stream 流对应元素的个数,【掐头】
Stream<T> limit(long n);
限制当前 Stream 对应的元素总个数,【去尾】
Stream<T> sorted();
对当前 Stream 流存储的进行排序操作,要求元素有自然顺序或者遵从 Comparable 接口,默认【升序】
Stream<T> sorted(Comparator<? super T> com);
对当前 Stream 流存储的进行排序操作,排序规则由 Comparator 函数式接口规范
Stream<T> filter(Predicate<? super T> pre);
判断过滤当前 Stream 流可以保存的数据条件,满足条件保留,不满足条件移除,过滤规则由 Predicate 接口约束
Stream<T> distinct();
当前 Stream 流中对应的所有元素去重擦操作
Stream<R> map(Function<T, R> fun);
当前 Stream 存储的数据情况转换为 Function 函数式接口要求的返回值类型,完成类型转换操作。
执行stream流的终止方法,stream流会自动关闭,对应stream占用空间会被JVM收回。常用的stream流终止方法有count计数,forEach,collect存储为集合,toArray转换为object类型数组。
方法的详细解释如下:
long count();
返回当前 Stream 流对应的数据元素个数,为终止方法。
void forEach(Consumer<? super T> con);
针对于当前 Stream 存储元素的处置方法,为终止方法。
<R, A> R collect(Collector<? super T, A, R> collector);
Stream 流对应的元素存储内容,转换为用户要求的 集合对象。终止方法
常用:
Collectors.toList() 目标存储集合类型为 List 集合
Collectors.toSet() 目标存储集合类型为 Set 集合
Object[] toArray();
Stream 流存储的元素内容转换为 Object 类型数组返回
3.相关代码演示
skip 和 limit
list.stream()
.skip(3)
.limit(14)
.forEach(System.out::println);
上述代码,创建集合的stream流,并对其中的数据进行跳过头三条数据,限制元素个数14的操作,相当于掐头去尾。
sort
ArrayList<Person> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(new Person("张三", (int) (Math.random() * 30), false));
}
/*
Stream<T> sorted(Comparator<? super T> comparator);
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
}
*/
list.stream()
.sorted((p1, p2) -> p2.getAge() - p1.getAge())
.forEach(System.out::println);
对集合中的Person对象按照年龄排序。p2.getAge() - p1.getAge()返回int类型数据,0是代表相等,正负代表升降序。
filter
/*
Stream<T> filter(Predicate<? super T> predicate);
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
*/
list.stream()
.filter(s -> s.length() > 3)
.distinct()
.forEach(System.out::println);
对s参数的长度进行过过滤,长度小于等于3的舍弃。
map
ArrayList<Person> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
int age = (int) (Math.random() * 50);
list.add(new Person("张三", age, false));
// Stream<Person> stream = list.stream();
// Stream<String> stream1 = stream.map(s -> s.toString());
list.stream()
.map(s -> s.getAge())
.limit(7)
.filter(s -> s > 40)
.forEach(System.out::println);
Lambda表达式s代表的是Person对象,返回值为存储s.getAge()的String对象,进行了类型转换,这里通过返回值约束泛型。
collect
List<String> list1 = list.stream()
.distinct()
.collect(Collectors.toList());
Set<String> collect = list.stream()
.limit(21)
.collect(Collectors.toSet());
collect返回list或者set集合,stream流结束。
最后值得注意的是,最终方法有且只可以用一次,如果多次使用,就会报异常:stream has already been operated upon or closed,提示当前Stream流已经关闭。