【Java】Stream流和方法引用
1 Stream流
1.1 Stream流优化过滤集合
传统方式
- 用一个循环过滤姓张的人
- 用一个循环过滤名字长度大于2的人
public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("张三三");list.add("张四四");list.add("李四四");ArrayList<String> newlist = new ArrayList<>();for(String s: list){if(s.startsWith("张")&&s.length()>2){listWithZhang.add(s);}}for(String s: newlist){System.out.println(s);}}
Stream流
JDK1.8后出现,关注做什么,而不是怎么做
public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("张三三");list.add("张四四");list.add("李四四");list.stream().filter((name)->name.startsWith("张")).filter((name)->name.length()>2).forEach((name)->{System.out.println(name);});}
1.2 流式思想概述
拼接流式模型:建立一个生产线,按照生产线来生产商品。
当使用一个流的时候,通常包括三个基本步骤:
- 获取一个数据源(source)→
- 数据转换→
- 执行操作获取想要的结果.
每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道。
1.3 获取流
java.util.stream.Stream<T> 是Java 8新加入的最常用的流接口。
(这并不是一个函数式接口。)
获取一个流有以下几种常用的方式:
- 所有的Collection集合都可以通过 stream 默认方法获取流;
- Stream 接口的静态方法 of 可以获取数组对应的流。
public static void main(String[] args) {//集合调用stream方法可以获得ArrayList<String> list = new ArrayList<>();Stream<String> stream1 = list.stream();//数组可以用Stream.of获得Stream<Integer> stream6 = Stream.of(1, 2, 3, 4, 5, 6);Integer[] arr = {1, 2, 3, 5};Stream<Integer> steam7 = Stream.of(arr);}
流的特点:Stream流属于管道流,只能使用一次,第一个流使用完毕就会关闭,这个流就不可以再调用其他方法了。
1.4 常用方法
流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:
- 延迟方法:返回值类型仍然是Stream 接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方法均为延迟方法。)
- 终结方法:返回值类型不再是Stream 接口自身类型的方法,因此不再支持类似StringBuilder 那样的链式调用。(例如:count 和forEach方法)。
forEach方法:forEach的参数是Consumer
//forEach的参数的Consumer//Consumer接口是一个消费型的函数式接口,可以传递lambda表达式消费数据public static void main(String[] args) {Stream<String> stream = Stream.of("张三", "李四", "王五");stream.forEach(name-> System.out.println(name));}
filter方法:filter的参数是Predicate,用于将一个流转换成另一个子集流
//forEach的参数是该接口接收一个Predicate//函数式接口参数(可以是一个Lambda或方法引用)作为筛选条件。//test方法将会产生一个boolean值结果,代表指定的条件是否满足。//如果结果为true,那么Stream流的filter 方法//将会留用元素;如果结果为false,那么filter 方法将会舍弃元素。public static void main(String[] args) {Stream<String> stream = Stream.of("张三", "张四","李四", "王五");Stream<String> stream1 = stream.filter((name) -> {return name.startsWith("张");});stream1.forEach(name-> System.out.println(name));}
map方法:
如果需要将流中的元素映射到另一个流中,可以用map。可以将T类型的流转换为R类型的流。java.util.stream.Function 函数式接口,其中唯一的抽象方法为:apply。这可以将一种T类型转换成为R类型,而这种转换的动作,就称为“映射”。
将integer类型转换为string类型
public static void main(String[] args) {Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);Stream<String> stream2 = stream.map((Integer i) -> {return String.valueOf(i);});stream2.forEach((s)-> System.out.println(s));}
count方法
用于统计Stream流中的元素个数。正如旧集合Collection 当中的size 方法一样,流提供count 方法来数一数其中的元素个数。count方法返回值是long类型的整数,是终结方法,,之后不能再继续调用其他方法。
public static void main(String[] args) {Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);long count = stream.count();System.out.println(count);}
limit方法:可以对流进行截取。参数是long类型的整数。属于延迟方法,可以继续调用其他方法。如果集合当前长度大于参数则进行截取;否则不进行操作,即还是原流。
public static void main(String[] args) {Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);stream.limit(3).forEach((num)-> System.out.println(num));}
skip方法:可以跳过前几个元素,获取一个截取之后的新流。参数超过元素个数,返回空流。
public static void main(String[] args) {Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);stream.skip(3).forEach((num)-> System.out.println(num));}
concat方法:组合两个流为一个流。concat是静态方法,通过接口名调用。
public static void main(String[] args) {Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);Stream<String> stream2 = Stream.of("a","b","c","d");Stream.concat(stream1,stream2).forEach((s)-> System.out.println(s));}
1.5 练习-集合元素处理
现在有两个ArrayList 集合存储队伍当中的多个成员姓名,要求使用传统的for循环(或增强for循环)依次进行以下若干操作步骤:
第一个队伍只要名字为3个字的成员姓名;
第一个队伍筛选之后只要前3个人;
第二个队伍只要姓张的成员姓名;
第二个队伍筛选之后不要前2个人;
将两个队伍合并为一个队伍;
根据姓名创建Person 对象;
打印整个队伍的Person对象信息。
Stream方式
public static void main(String[] args) {ArrayList<Person> list1 = new ArrayList<>();list1.add(new Person("李白"));list1.add(new Person("杜甫"));list1.add(new Person("李清照"));list1.add(new Person("王勃"));list1.add(new Person("刘禹锡"));list1.add(new Person("辛弃疾"));list1.add(new Person("龚自珍"));ArrayList<Person> list2 = new ArrayList<>();list2.add(new Person("李四"));list2.add(new Person("王五"));list2.add(new Person("张一"));list2.add(new Person("张二"));list2.add(new Person("张三"));Stream<Person> newlist1 = list1.stream().filter((person) -> {return person.getName().length() == 3;}).limit(3);Stream<Person> newlist2 = list2.stream().filter((person) -> {return person.getName().startsWith("张");}).skip(2);Stream.concat(newlist1, newlist2).forEach((person)-> System.out.println(person));}
2 方法引用
2.1 应用:简化lambda
双冒号:: 为引用运算符,而它所在的表达式被称为方法引用。如果Lambda要表达的函数方案已经存在于某个方法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者。
例如上方代码中的最后一句可以等价为:
Stream.concat(newlist1, newlist2).forEach((person)-> System.out.println(person));
Stream.concat(newlist1, newlist2).forEach(System.out::println);
2.2 通过对象名引用成员方法
自定义一个接口
public interface Printable {void print(String s);
}
自定义一个类及其成员方法
public class MethodRerObject {public void printUpperCaseString(String str){System.out.println(str.toUpperCase());}
}
测试
public class Test {//通过对象名引用成员方法//前提:对象名存在,成员方法存在public static void printString(Printable p){p.print("Hello");}public static void main(String[] args) {//用lambdaprintString((s)->{MethodRerObject obj = new MethodRerObject();obj.printUpperCaseString(s);});//方法引用优化//对象和成员方法都存在MethodRerObject obj = new MethodRerObject();printString(obj::printUpperCaseString);}
}
2.3 通过类名引用静态成员方法
定义一个函数式接口
@FunctionalInterface
public interface Calcable {int calAbs(int num);
}
定义一个方法传递接口和整数
public class Test {public static int method(int number, Calcable c){return c.calAbs(number);}public static void main(String[] args) {//调用method方法int result = method(-10, (num) -> Math.abs(num));System.out.println(result);//使用方法引用优化 Math存在 abs的静态方法也存在int result2 = method(-10, Math::abs);System.out.println(result2);}
}
2.4 通过super引用父类成员方法
定义函数式接口
public interface Greatable {void great();
}
定义父类
public class Human {public void sayHello(){System.out.println("Hello, i am human");}
}
定义子类
public class Man extends Human{@Overridepublic void sayHello(){System.out.println("Hello, i am man");}public void great(Greatable g){g.great();}public void show(){great(()->{Human h = new Human();h.sayHello();});//通过父类调用great(()->{super.sayHello();});//通过父类引用great(super::sayHello);}public static void main(String[] args) {new Man().show();}
}
2.5 通过this引用本类成员方法
public interface Richable {void buy();
}
public class Husband {public void buyHouse(){System.out.println("买房子");}public void marry(Richable r){r.buy();}public void soHappy(){//this和buyHouse都是以及存在的 可以直接用this来引用本类方法//marry(()->this.buyHouse());marry(this::buyHouse);}public static void main(String[] args) {new Husband().soHappy();}
}
2.6 类的构造器引用
自定义一个Person类,自定义一个创建Person的接口
public interface PersonBuilder {Person buildPerson(String name);
}
public class Test {public static void printName(String name, PersonBuilder pb){Person person = pb.buildPerson(name);System.out.println(person.getName());}public static void main(String[] args) {//调用method方法printName("张三",(name)->new Person(name));//使用方法引用优化 Person的构造方法已知 创建对象new已知printName("李四", Person::new);}
}
2.7 数组的构造器引用
@FunctionalInterface
public interface ArrayBuilder {int[] buiderArray(int length);
}
public class Test {public static int[] createArray(int len, ArrayBuilder ab){return ab.buiderArray(len);}public static void main(String[] args) {//调用method方法int[] array = createArray(10, (len) ->new int[len]);System.out.println(array.length);//使用方法引用优化lambda 已知创建的是int类型的数组 数组的长度已知int[] array1 = createArray(10, int[]::new);System.out.println(array1.length);}
}
【Java】Stream流和方法引用相关推荐
- Stream流、方法引用知识梳理
Stream流.方法引用 第一章 Stream流 这里的Stream流不是IO Stream 因为Lambda引入的函数式编程在java8中有一个全新的Stream概念,用于解决已有集合类库的弊端 1 ...
- 【Stream流、方法引用】
Java基础 第二十四章 Stream流.方法引用 今日内容 Java基础 Stream流 流与集合 传统集合的多步遍历代码 循环遍历的弊端 Stream的更优写法 流式思想概述 获取流 根据Coll ...
- 2022/07/17、18 day10/11:Stream流、方法引用
文章目录 1. Stream流 1.1 引言 1.2 流式思想概述 1.3 获取流 1.4 常用方法 1.5 练习:集合元素处理(传统方式) 1.6 练习:集合元素处理(Stream方式) 2. 方法 ...
- java day24【Stream流、方法引用】
第一章 Stream流 说到Stream便容易想到I/O Stream,而实际上,谁规定"流"就一定是"IO流"呢?在Java 8中,得益于Lambda所带来的 ...
- Java笔记_16(不可变集合、Stream流、方法引用)
Java笔记_16 一.创建不可变集合 1.1.创建不可变集合的应用场景 1.2.创建不可变集合的书写格式 二.Stream流 2.1.体验Stream流 2.2.Stream流的思想和获取Strea ...
- Lambda表达式,Stream流,方法引用,Base64(JDK8新特性)
Labda表达式 Lambda表达式演示 Lanbda表达式:是JDK1.8提出的一种新语法.是对之前的某种情况的代码的"简化写法". Lambda表达式演示: public cl ...
- java Stream 流
java Stream 流 Stream 流 流的创建 流的转化 Optianal 流的计算 Stream 流 1. Stream的定义 来自数据源的支持聚合操作的元素序列. 即一个流对外提供接口,接 ...
- Java stream流式计算详解
Java stream流式计算详解 1. Stream概述 1.1 Stream简介 1.2 Stream分类 2. Stream操作 2.1 Stream创建 2.2 Stream无状态操作 2.3 ...
- 【Java 8 新特性】Java Stream 通过skip()方法跳过前N个子元素
[Java 8 新特性]Java Stream 通过skip方法跳过前N个子元素 1.skip() 示例 2.skip() vs limit() 参考文献 本页将介绍 Stream.skip方法示例. ...
最新文章
- 欧拉定理 费马小定理
- 某集团公司信息化项目经验总结
- JavaWeb系列之:Servlet
- 查看、关闭当前服务器上启动服务 / 进程
- java .equal_Java中的equals()
- 4.namespace
- 李航《统计学习方法》多项式函数拟合问题--最小二乘法
- Ubuntu下Opencv安装与使用
- 联想微型计算机改win7,联想win10改win7如何实现?联想电脑Win10改Win7方法详解
- 计算机维修.pdf,计算机维修(中).pdf
- C-11 Problem H: 开宝箱2
- 女程序员南漂3年:有种心酸叫孤单的人总是晚回家
- 学习笔记(2):A110测试-测试课程申请1888
- 核心单词Word List 50
- 旷视科技2018暑期实习-算法研究员面试记
- 【i学堂】PPT美化
- 如何做抖音自媒体?这些小技巧一定要掌握
- 知乎1w视频播放能赚多钱?今天来大揭秘
- abb机器人--示教器--基础认识
- JBuilder的基本使用
热门文章
- 一文读懂 | 进程并发与同步
- Linux C Socket编程,这篇文章让我耳目一新
- C语言必须写main函数?最简单的 Hello world 你其实一点都不懂!
- 看看大神是如何计算32位数中‘1’的个数
- kafka rabbitmq优劣对比_Kafka、RabbitMQ、RocketMQ等消息中间件的对比
- Express 路由模块化以及 Express 应用程序生成器
- pypinyin 获取多音字的拼音组合
- LeetCode 1825. 求出 MK 平均值(set + queue)
- LeetCode 510. 二叉搜索树中的中序后继 II(查找右子树或者祖父节点)
- NumPy快速入门--复制/视图/深拷贝