JDK1.8新特性——Stream流方法引用

文章目录

  • Stream流
    • 如何获取流水线
    • Stream流中间方法
    • Stream终结方法
  • 方法引用
      • 引用静态方法
      • 引用成员方法
      • 引用构造方法
      • 类名引用成员方法
      • 引用数组构造方法


Stream流

Stream流是JDK8中提供的一种新特性

Stream流的使用步骤:

  1. 先得到Stream流,把数据放到流中
  2. 使用中间方法对流水线上的数据进行操作
    • 中间方法:过滤、转换(方法调用完毕后还可以调用其他方法)
  3. 使用终结方法对流水线上的数据进行操作
    • 终结方法:统计、打印(最后一步操作,方法调用完毕之后不能再去调用其他方法)

如何获取流水线

获取方式方法名说明
单例集合default Stream<E> stream()Collection中的默认方法
双列集合无法直接使用stream流
数组public static <T> Stream<T> stream(T[] array)Arrays工具类中的静态方法
零散数据public static<T> Stream<T>of(T… values)Stream接口中的静态方法,需要同种数据类型

单列集合获取Stream流

//集合的批量添加
List<String> list = new ArrayList<String>(){{add("张无忌");add("周芷若");add("赵敏");add("张三丰");add("张翠山");add("王二麻子");add("谢广坤");add("马超");add("张良");}
};
// 获取stream流并打印
list.stream().forEach(s -> System.out.println(s));

双列集合获取Stream流

Map<Integer,String> map = new HashMap<Integer,String>(){{put(1,"张无忌");put(2,"周芷若");put(3,"赵敏");}
};
// 直接获取map中的key
map.keySet().stream().forEach(k -> System.out.println(k));
// 获取map中的value
map.values().stream().forEach(v -> System.out.println(v));
// 获取键值对
map.entrySet().stream().forEach(e-> System.out.println(e));

数组获取Stream流

String[] str = {"张无忌","周芷若","赵敏","张三丰","张翠山","王二麻子","谢广坤","马超","张良"};
// 数组转集合
List<String> collect = Arrays.stream(str).collect(Collectors.toList());
System.out.println(collect);

零散数据获取Stream流

前提零散数据类型是一样的

Stream.of("张无忌","周芷若","赵敏","张三丰","张翠山","王二麻子","谢广坤","马超","张良").forEach(s -> System.out.println(s));

Stream流中间方法

名称说明
Stream<T> filter(Predicate<? super T> predicate)过滤
Stream<T> limit(long maxSize)获取前几个元素
Stream<T> skip(long n)跳过前几个元素
Stream<T> distinct()元素去重,依赖(hashCode和equals方法)
static <T> Stream<T> concat(Stream a, Stream b)合并a和b两个流为一个流
Stream<R> map(Function<T, R> mapper)转换流中的数据类型
  • 注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
  • 注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据

filter方法

该方法返回true表示保留该数据,false表示过滤掉该数据

public static void main(String[] args) {//集合的批量添加List<String> list = new ArrayList<String>() {{add("张无忌");add("周芷若");add("赵敏");add("张三丰");add("张翠山");add("王二麻子");add("谢广坤");add("马超");add("张良");}};// s表示集合里的每一条数据list.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return false;}});// 打印以张开头的前两条数据list.stream().filter(s -> s.startsWith("张")).limit(2).forEach(s -> System.out.println(s));}

concat方法

concat方法是Stream的静态方法,作用是将两个Stream流合并成一个,注意如果两个流的数据类型不一致就会将类型提示为他们共同的父类。

//集合的批量添加List<String> list = new ArrayList<String>() {{add("张无忌");add("周芷若");add("赵敏");add("张三丰");add("张翠山");add("王二麻子");add("谢广坤");add("马超");add("张良");}};Stream.concat(list.stream(),list.stream()).forEach(s -> System.out.println(s));

map方法

打印每个人的年龄

public static void main(String[] args) {//集合的批量添加List<String> list = new ArrayList<String>() {{add("张无忌-22");add("周芷若-20");add("赵敏-20");add("张三丰-70");add("张翠山-50");add("王二麻子-20");add("谢广坤-44");add("马超-35");add("张良-30");}};// 匿名内部类写法list.stream().map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {String[] split = s.split("-");int ret = Integer.parseInt(split[1]);return ret;}}).forEach(s->System.out.println(s));// lambda写法,在forEach中s已经编程整形list.stream().map(s->Integer.parseInt(s.split("-")[1])).forEach(s->System.out.println(s));}
}

Stream终结方法

名称说明
void forEach(Consumer action)遍历
long count()统计
toArray()收集流中的数据放到数组中
collect(Collector collertor)收集流中的数据,放到集合中

toArray()方法

public static void main(String[] args) {//集合的批量添加List<String> list = new ArrayList<String>() {{add("张无忌");add("周芷若");add("赵敏");add("张三丰");add("张翠山");add("王二麻子");add("谢广坤");add("马超");add("张良");}};// 匿名内部类写法String[] array = list.stream().toArray(new IntFunction<String[]>() {/**** @param value 数组的容量* @return*/@Overridepublic String[] apply(int value) {return new String[value];}});System.out.println(Arrays.toString(array));// lambda写法String[] array1 = list.stream().toArray(value -> new String[value]);System.out.println(Arrays.toString(array1));}

collect方法

收集为List或者Set是比价简单的

public static void main(String[] args) {//集合的批量添加List<String> list = new ArrayList<String>() {{add("张无忌-男-22");add("周芷若-女-20");add("赵敏-女-20");add("张三丰-男-66");add("张翠山-男-55");add("谢广坤-男-35");add("马超-男-30");add("张良-男-29");}};// 将所有男性收集到一个List中List<String> ret = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toList());// 将素所有女性收集到一个Set中Set<String> set =  list.stream().filter(s -> "女".equals(s.split("-")[1])).collect(Collectors.toSet());System.out.println(ret);System.out.println(set);}

来看一下收集到Map里,将姓名和年龄形成一个键值对。

注意:使用toMap收集流中的数据时,key是不能重复的,否则会抛出异常

public static void main(String[] args) {//集合的批量添加List<String> list = new ArrayList<String>() {{add("张无忌-男-22");add("周芷若-女-20");add("赵敏-女-20");add("张三丰-男-66");add("张翠山-男-55");add("谢广坤-男-35");add("马超-男-30");add("张良-男-29");}};// 匿名内部类写法/*** toMap的第一个函数接口参数:*    泛型参数:key: 表示流的数据类型*    泛型参数 value: 表示要转换Map的key的数据类型* toMap的第二个函数接口参数:*    泛型参数:key: 表示流的数据类型*    泛型参数 value: 表示要转换Map的value的数据类型*/Map<String,Integer> map1 = list.stream().collect(Collectors.toMap(new Function<String, String>() {/*** 该方法的参数就是流中的元素* 该方法的返回值就是Map的key* @param s the function argument* @return*/@Overridepublic String apply(String s) {return s.split("-")[0];}},new Function<String, Integer>() {/*** 该方法的参数就是流中的元素* 该方法的返回值就是Map的value* @param s the function argument* @return*/@Overridepublic Integer apply(String s) {return Integer.parseInt(s.split("-")[2]);}}));// lambda写法Map<String ,Integer> map2 = list.stream().collect(Collectors.toMap(s -> s.split("-")[0],s->Integer.parseInt(s.split("-")[2])));System.out.println(map1);System.out.println(map2);
}

方法引用

方法引用就是把已经有的方法拿过来用,当做函数式接口中抽象方法的方法体

使用方法引用需要注意以下4点:

  1. 引用处必须是函数式接口
  2. 被引用的方法必须已经存在
  3. 被引用方法的形参和返回值需要跟抽象方法保持一致
  4. 被引用方法的功能要满足当前需求

举个例子,我们要对一个数组进行降序排序。

public static void main(String[] args) {Integer[] arr = {1,6,8,3,4,6,7,5,2,9};// 使用匿名内部类Arrays.sort(arr, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2-o1;}});// 使用lambda表达式Arrays.sort(arr, (o1, o2) -> o2-o1);System.out.println(Arrays.toString(arr));
}

我们可以通过方法引用的方式来进行

Arrays.sort的第二个参数比较规则,是函数式接口满足要求,其余3点也满足就可以使用方法引用。

public static void main(String[] args) {Integer[] arr = {1,6,8,3,4,6,7,5,2,9};// 使用方法引用Arrays.sort(arr, Main::cmp);System.out.println(Arrays.toString(arr));}
public static int cmp(int a,int b){return b-a;
}

::是一个方法引用符号

引用静态方法

  • 格式:类名::静态方法
  • 示例:Integer::parseInt

比如将一组字符串数组转换成整形数字,直接将Integer的静态方法拿过来用即可

public static void main(String[] args) {List<String> list = new ArrayList<String>(){{add("1");add("2");add("3");add("4");add("5");}};// 匿名内部类写法List<Integer> ret1 = list.stream().map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s);}}).collect(Collectors.toList());System.out.println(ret1);// 使用方法引用写法List<Integer> ret2 = list.stream().map(Integer::parseInt).collect(Collectors.toList());System.out.println( ret2);
}

引用成员方法

  • 格式: 对象::成员方法
  1. 其他类:其他对象::方法名
  2. 本类:this::方法名(引用处不能是静态方法)
  3. 父类:super::方法名(引用处不能是静态方法)

需求:打印性张且名字长度为3个字人

调用其他类的成员方法

class Test{public boolean filter(String s) {return s.startsWith("张") && s.length() == 3;}
}
public class Main {public static void main(String[] args) {//集合的批量添加List<String> list = new ArrayList<String>() {{add("张无忌");add("周芷若");add("赵敏");add("张三丰");add("张翠山");add("谢广坤");add("马超");add("张良");}};// 匿名内部类写法list.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return s.startsWith("张") && s.length() == 3;}}).forEach(s -> System.out.println(s));// 方法引用,引用其他类方法Test test = new Test();list.stream().filter(test::filter).forEach(s -> System.out.println(s));}}

引用本类的成员方法

需求:打印性张且名字长度为3个字人

public class Main {public boolean filter(String s) {return s.startsWith("张") && s.length() == 3;}public  void main(String[] args) {//集合的批量添加List<String> list = new ArrayList<String>() {{add("张无忌");add("周芷若");add("赵敏");add("张三丰");add("张翠山");add("谢广坤");add("马超");add("张良");}};// 方法引用,引用本类类方法list.stream().filter(new Main()::filter).forEach(s -> System.out.println(s));}}

引用父类的成员方法

class Test {public boolean filter(String s) {return s.startsWith("张") && s.length() == 3;}
}public class Main extends Test {public boolean filter(String s) {return s.startsWith("张") && s.length() == 3;}public  void func() {//集合的批量添加List<String> list = new ArrayList<String>() {{add("张无忌");add("周芷若");add("赵敏");add("张三丰");add("张翠山");add("谢广坤");add("马超");add("张良");}};// 方法引用,引用父类方法list.stream().filter(super::filter).forEach(System.out::println);}}

引用构造方法

  • 格式:类名::new

需求:将字符串张三-22构成User对象

class User {String username;int age;public User(String username, int age) {this.username = username;this.age = age;}public User(String str) {String[] split = str.split("-");this.username = split[0];this.age = Integer.parseInt(split[1]);}@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", age=" + age +'}';}
}public class Main  {public boolean filter(String s) {return s.startsWith("张") && s.length() == 3;}public  static void main(String[] args) {//集合的批量添加List<String> list = new ArrayList<String>() {{add("张无忌-22");add("周芷若-20");add("赵敏-20");add("张三丰-60");add("张翠山-35");}};// 匿名内部类写法List<User> userList1 = list.stream().map(new Function<String, User>() {@Overridepublic User apply(String str) {String[] split = str.split("-");return new User(split[0], Integer.parseInt(split[1]));}}).collect(Collectors.toList());System.out.println(userList1);// 使用构造方法引用写法,拿User类的构造方法作为参数List<User> userList2 = list.stream().map(User::new).collect(Collectors.toList());System.out.println(userList2);}}

类名引用成员方法

  • 格式:类名::成员方法
  • 示例:String::toUpperCase

这种通过类名引用成员方法的方式有点特别,需要遵循以下规则,

方法引用的规则:

  1. 需要有函数式接口
  2. 被引用的方法必须已经存在
  3. 被引用方法的形参,需要跟抽象方法的第一个参数到最后一个形参保持一致,返回值需要保持一致
  4. 被引用方法的功能需要满足当前的需求

抽象方法形参注意事项:

  • 第一个参数:表示被引用方法的调用者,决定了可以引用哪些类的方法,在Stream流当中,第一个参数一般都表示流里面的每一个数据,假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用String这个类中的方法
  • 第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法

需求:将一堆字符串都转换成大写

  • 首先Function是一个函数式接口,它只有一个抽象方法apply
  • apply方法的第一个形参是String类型,那么就觉得了只能引用String中的方法
  • apply方法没有第二个形参说明引用的方法需要是无参的
  • 那么引用String中的toUpperCase是符合要求的
public  static void main(String[] args) {List<String> stringList = Arrays.asList("aa","bb","cc","dd");// 匿名内部类写法List<String> ret1 = stringList.stream().map(new Function<String, String>() {@Overridepublic String apply(String s) {return s.toUpperCase();}}).collect(Collectors.toList());System.out.println(ret1);// 方法引用写法List<String> ret2 = stringList.stream().map(String::toUpperCase).collect(Collectors.toList());System.out.println(ret2);}
public String toUpperCase() {return toUpperCase(Locale.getDefault());
}

局限性:

  • 不能引用所有类中的成员方法。
  • 是跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法

引用数组构造方法

  • 格式:数据类型[]:new
  • 示例:int[]::new

需求将List中的数据放到一个新数组中

public  static void main(String[] args) {List<Integer> list = new ArrayList<Integer>(){{add(1);add(2);add(3);add(4);add(5);}};// 匿名内部类写法Integer[] array = list.stream().toArray(new IntFunction<Integer[]>() {@Overridepublic Integer[] apply(int value) {return new Integer[value];}});System.out.println(Arrays.toString(array));// 方法引用写法Integer[] array2 = list.stream().toArray(Integer[]::new);System.out.println(Arrays.toString(array2));
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/766838.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

七、大模型-什么是Fine-tuning

好文推荐 推荐一篇比较透彻的介绍 对于深度学习模型中的 Fine-tuning&#xff08;微调&#xff09;操作&#xff0c;以下是详细介绍和原理说明&#xff1a; 什么是 Fine-tuning&#xff08;微调&#xff09;&#xff1f; Fine-tuning 是指在一个已经训练好的模型基础上&am…

Arcgis 导入经纬度坐标、导出经纬度坐标

目录 一、导入经纬度坐标 1、在excel中准备好经纬度坐标的数据表 2、将数据放入Acrgis的工作路径 3、在arcgis中添加数据 4、显示经纬度坐标点 5、导出为shp矢量文件 二、根据shp的经纬度坐标点导出成经纬度坐标 1、右键选择打开属性表 2、在属性表的菜单下拉栏里找到…

三、阅读器的开发--1、项目准备

1、项目准备 1.1、项目搭建 我用的脚手架是vue cli 5.0的&#xff0c;通过vue create 项目名称来创建的项目 上下箭头选的是最后那个&#xff0c;是指手动配置&#xff0c;然后回车 空格选中下面这些&#xff0c;然后回车 下图最后那个指我们所有的配置在哪里配置&#xff0…

c++ 线程池/Github 开源项目源码分析(progschj/ThreadPool)

c 线程池/Github 开源项目源码分析&#xff08;progschj/ThreadPool&#xff09; 前言[ThreadPool 项目地址](https://github.com/progschj/ThreadPool)项目源码&#xff1a;基本用法类成员变量类成员函数构造函数的签名创建线程线程默认的任务向任务队列中添加一个任务析构函数…

open images v7的600类别名称

英文&#xff1a; 0: Accordion1: Adhesive tape2: Aircraft3: Airplane4: Alarm clock5: Alpaca6: Ambulance7: Animal8: Ant9: Antelope10: Apple11: Armadillo12: Artichoke13: Auto part14: Axe15: Backpack16: Bagel17: Baked goods18: Balance beam19: Ball20: Balloon21…

【Rust】Shared-State Concurrency

Shared-State Concurrency channel类似于single ownership. 而shared memory类似与multiple ownership. multiple ownership是难于管理的. smarter pointer也是multiple ownership的. Rust的type system和ownership rules帮助实现正确的multiple ownership管理。 Using Mute…

百度智能云+SpringBoot=AI对话【人工智能】

百度智能云SpringBootAI对话【人工智能】 前言版权推荐百度智能云SpringBootAI对话【人工智能】效果演示登录AI对话 项目结构后端开发pom和propertiessql_table和entitydao和mapperservice和implconfig和utilLoginController和ChatController 前端开发css和jslogin.html和chat.…

MySQL 8.0-索引- 不可见索引(invisible indexes)

概述 MySQL 8.0引入了不可见索引(invisible index)&#xff0c;这个在实际工作用还是用的到的&#xff0c;我觉得可以了解下。 在介绍不可见索引之前&#xff0c;我先来看下invisible index是个什么或者定义。 我们依然使用拆开来看&#xff0c;然后再把拆出来的词放到MySQL…

kali安装docker(亲测有效)

第一步&#xff1a;添加Docker官方的GPG密钥 curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - 第二步&#xff1a; 第二步更新源 echo deb https://download.docker.com/linux/debian stretch stable> /etc/apt/sources.list.d/docker.list…

数据结构——树与二叉树

目录 树与二叉树 1.树的定义 2.树的有关术语 3.二叉树&#xff08;BinaryTree&#xff09; 二叉树的性质&#xff1a; 特殊的二叉树 满二叉树&#xff1a; 完全二叉树 二叉树的存储结构 顺序存储结构 链式存储结构 二叉树以及对应接口的实现 1.二叉树架构搭建 2…

关于 Microsoft Visual Studio

关于 Microsoft Visual Studio References References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

hive学习记录

问题集合 Q&#xff1a;终端启动hive时报错&#xff1a;/tmp/hive on HDFS should be writable&#xff1f; A&#xff1a;hdfs dfs -chmod 777 /tmp/hive Q&#xff1a;hive&#xff1a; unable to create database path file…错误 A&#xff1a;在hive-site.xml里面添加以…

【机器学习300问】47、如何计算AUC?

一、AUC是什么&#xff1f; &#xff08;1&#xff09;文绉绉的定义 AUCArea Under the Curve中文直译叫“曲线下面积”&#xff0c;AUC名字里面的Curve曲线指的就是ROC曲线&#xff0c;关于ROC曲线的相关知识我已经在之前的文章中详细说过了&#xff0c;有需要的友友可以点击…

CI/CI实战-jenkis结合gitlab 4

实时触发 安装gitlab插件 配置项目触发器 生成令牌并保存 配置gitlab 测试推送 gitlab的实时触发 添加jenkins节点 在jenkins节点上安装docker-ce 新建节点server3 安装git和jdx 在jenkins配置管理中添加节点并配置从节点 关闭master节点的构建任务数

[Java安全入门]六.CC3

一.前言 前几天学了一下cc1和cc6&#xff0c;对于我来说有点小困难&#xff0c;不过经过几天沉淀&#xff0c;现在也是如拨开云雾见青天&#xff0c;经过一上午的复习对cc1和cc6又有深入的了解。所以&#xff0c;今天想多学一下cc3。cc3执行命令的方式与cc1和cc6不一样&#x…

C#基础-标识符命名规则

目录 1、标识符定义 2、遵循规则 3、标识符的例子 4、MSDN中英文解释 英文

Debezium日常分享系列之:Debezium2.5稳定版本之Monitoring

Debezium日常分享系列之&#xff1a;Debezium2.5稳定版本之Monitoring 一、Snapshot metrics二、Streaming metrics三、Schema history metrics Debezium系列之&#xff1a;安装jmx导出器监控debezium指标 除了 Zookeeper、Kafka 和 Kafka Connect 提供的对 JMX 指标的内置支持…

革新水库大坝监测:传统软件与云平台之比较

在水库大坝的监测管理领域&#xff0c;传统监测软件虽然曾发挥了重要作用&#xff0c;但在多方面显示出了其局限性。传统解决方案通常伴随着高昂的运维成本&#xff0c;需要大量的硬件支持和人员维护&#xff0c;且软件整合和升级困难&#xff0c;限制了其灵活性和扩展性。 点击…

Neo4j桌面版导入CVS文件

之后会出来一个提示框&#xff0c;而且会跳出相关文件夹&#xff1a; 然后我们将CSV文件放在此目录下&#xff1a; 我们的relation.csv是这样的 参见&#xff1a; NEO4J的基本使用以及桌面版NEO4J Desktop导入CSV文件_neo4j desktop使用-CSDN博客

C++11:左值与右值|移动构造|移动赋值

​ &#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;マイノリティ脈絡—ずっと真夜中でいいのに。 0:24━━━━━━️&#x1f49f;──────── 4:02 &#x1f504; …