教你会用Lambda和Stream流

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流已经关闭。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值