文章目录
初识Stream流
Stream流把真正的函数式编程风格引入到java中
案例:需求:
创建集合,存储多个字符串元素;把集合中“张”开头的字符串存储到另外的集合中;把“张”开头的集合中的长度大于3的元素存储到另外集合中;遍历上一步得到的集合。
package itiheima314.test5;
public class StreamDemo {
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<String>();
array.add("林俊杰");
array.add("张信哲");
array.add("王一博");
array.add("许嵩");
array.add("张杰");
array.add("张艺兴");
ArrayList<String> zhang = new ArrayList<String>();
for(String s:array){
if(s.startsWith("张")){
zhang.add(s);
}
}
System.out.println( "zhang集合:"+zhang);
ArrayList<String> zhang3 = new ArrayList<String>();
for(String s :zhang){
if(s.length() == 3){
zhang3.add(s);
}
}
System.out.println("zhang3集合:" + zhang3);
System.out.println("-----------");
// 使用stream流实现
array.stream().filter(s->s.startsWith("张")).filter(s-> s.length() == 3).forEach(s-> System.out.println(s));
* 注意:
* 意思:array.stream生成流、过滤张、过滤长度为3、forEach逐一打印
// 使用引用类方法简化
System.out.println("简化");
array.stream().filter(s -> s.startsWith("张")).filter(s -> s.length()==3).forEach(System.out::println);
}
}
注意
2022/4/22 |
---|
String类中的startsWith方法 boolean startsWith(String prefix) 判断此字符串是否以指定的前缀prefix开头 |
Stream流的生成方式
Stream的使用:
1 生成流
通过数据源(集合、数组等)生成流
list.stream()
2 中间操作
一个流后面可以跟随零个或多个中间操作,其目的主要是打开流,
做出某种程度的数据过滤/映射,然后返回一个新的流,交给下一个操作使用。
filter()
3 终结操作
一个流只能有一个终结操作,当这个操作执行后,流就被使用“光”了,无法再被操作。
forEach()
Stream流的返回值是:Stream < T > streamName
Stream流的常见生成方式:
1 Collection体系的集合可以使用默认方法stream()生成流
default Stream< E > stream()
// 集合.stream();
2 Map 体系的集合间接的生成流
可以使用方法keySet方法、values方法、entrySet方法
// 集合.keySet().stream();
3 数组可以通过Stream接口的静态方法of(T...values)生成流
其中静态方法of(T....values)是可变参数。
Stream.of(T...values)
// Stream.of(数组);
代码:
package itiheima314.test5;
public class StreamDemo1 {
public static void main(String[] args) {
* Collection体系的集合可以使用默认方法stream()生成流
// List 和 Set 是Collection的儿子 还有一个Queue
List<String> list = new ArrayList<String>();
Stream<String> listStream = list.stream();
Set<String> set = new HashSet<String>();
Stream<String> setStream = set.stream();
* Map 体系的集合间接的生成流
Map<String,Integer> map = new HashMap<String, Integer>();
Stream<String> keyStrem = map.keySet().stream();
// map.ksySet得到是 键的集合,集合通过stream方法可以得到stream流
Stream<Integer> valueStream = map.values().stream();
// map.values 得到 值的集合,集合通过stream方法可以得到stream流
Stream<Map.Entry<String, Integer>> kvStream = map.entrySet().stream();
// map.entrySet 得到键值对 对象的集合
* 数组可以通过Stream接口的静态方法of(T...values)生成流
String[] strArray = {"you","are","my","pretty","sunshine"};
Stream<String> strArray1 = Stream.of(strArray);
Stream<String> strStream2 = Stream.of("hello", "world");
Stream<Integer> integerStream = Stream.of(10, 20, 30);
}
}
Stream流的中间操作方式
中间操作方法:
方法名 | 说明 |
---|---|
Stream < T > filter(Predicate predicate) | 用于对流中的数据进行过滤 Predicate接口中的抽象方法,boolean test(T t):对给定的参数进行操作,返回一个布尔值 filter参数采用Lambda表达式,因为参数满足 是一个接口,且只有一个抽象方法test |
Stream< T > limit(long maxSize) | 返回此流中的元素组成的流,截取前指定参数个数的数据 |
Stream< T > skip(long n) | 跳过指定参数个数的数据,返回由该流的剩余元素组成的流 |
static < T > Stream < T > concat(Stream a,Stream b) | 合并a和b两个流为一个流 |
Stream< T > distinct() | 返回由该流的不同元素(Object.equals(Object))组成的流 |
Stream< T > sorted() | 返回由此流的元素组成的流,根据自然顺序排序 |
Stream< T > sorted(Comparator comparator | 返回由该流的元素组成的流,根据提供的Comparator进行排序 Comparator接口中的方法 int compare(T o1,T o2) |
< R > Stream < R > map(Function mapper) | 返回由给定函数应用于此流的元素的结果组成的流 Function接口中的方法 R apply(T t) |
IntStream mapToInt(ToIntFunction mapper) | 返回一个IntStream,其中包含将给定函数应用于此流的元素的结果 IntStream 表示原始int流ToIntFunction接口中的方法 int applyAsInt(T value) 其中IntStream接口中有方法int sum() 返回此流中元素的总和 |
案例1:filter
package itiheima314.test5;
public class StreamDemo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("林俊杰");
list.add("张信哲");
list.add("王一博");
list.add("胡夏");
list.add("张杰");
list.add("张艺兴");
* 需求1:把list集合中的以张开头的元素在控制台输出
// 流生成方式1 Collection集合中静态方法Stream方法
list.stream().filter((String s) -> s.startsWith("张")).forEach((String s)-> System.out.println(s));
// 省略 引用类的方法 对象::实例方法
list.stream().filter(s->s.startsWith("张")).forEach(System.out::println);
System.out.println("-----------------");
* 需求2:把list集合中长度为3的元素在控制台输出
// 对象::实例方法
list.stream().filter(s->s.length() == 3).forEach(System.out::println);
System.out.println("------");
* 需求3:把list集合中以张开头,长度为3的元素在控制台输出
list.stream().filter(s->s.startsWith("张")).filter(s->s.length() == 3).forEach(System.out::println);
}
}
案例2:limit skip
package itiheima314.test5;
public class StreamDemo3 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("林俊杰");
list.add("张信哲");
list.add("王一博");
list.add("胡夏");
list.add("张杰");
list.add("张艺兴");
* 需求1:取前三个数据在控制台输出
list.stream().limit(3).forEach(System.out::println);
// 输出结果是:林俊杰 张信哲 王一博
System.out.println("-------");
* 需求2:跳过3个数据,把剩下的元素在控制台输出
list.stream().skip(3).forEach(System.out::println);
// 输出结果是:胡夏 张杰 张艺兴
System.out.println("-----");
* 需求3:跳过2个元素,把剩下的元素中前2个在控制台输出
list.stream().skip(2).limit(2).forEach(System.out::println);
// 输出结果:王一博 胡夏
}
}
案例3:dictinct concat
package itiheima314.test5;
public class StreamDemo4 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("林俊杰");
list.add("张信哲");
list.add("王一博");
list.add("胡夏");
list.add("张杰");
list.add("张艺兴");
* 需求1:取前4个数组成一个流
Stream<String> s1 = list.stream().limit(4);
* 需求2:跳过2个数据组成一个流
Stream<String> s2 = list.stream().skip(2);
* 需求3:合并需求1和需求2得到的流,并把结果在控制台输出
Stream.concat(s1, s2).forEach(System.out::println);
* 需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
// 输出:林俊杰 张信哲 王一博 胡夏 王一博 胡夏 张杰 张艺兴
System.out.println("---------");
Stream.concat(s1, s2).distinct().forEach(System.out::println);
// 输出结果:林俊杰 张信哲 王一博 胡夏 张杰 张艺兴
}
}
注意
2022/4/22 |
---|
同时执行两个forEach流终端操作会报错,IllegalStateException: stream has already been operated upon or closed 流只能运行终端流操作一次 |
案例4:sorted
package itiheima314.test5;
public class StreamDemo5 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("linqingxia");
list.add("zhangmanyu");
list.add("wangzuxian");
list.add("liuyan");
list.add("zhangmin");
list.add("zhagnwuji");
* 需求1:按照字母顺序把数据在控制台输出
list.stream().sorted().forEach(System.out::println);
// 输出结果 :首字母相同的时候,按照添加顺序输出
//linqingxia
//liuyan
//wangzuxian
//zhangmanyu
//zhangmin
//zhangwuji
* 需求2:按照字符串长度把数据在控制台输出
// 匿名内部类
list.stream().sorted(new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
}).forEach(System.out::println);
// 输出结果有问题:其中 后三个没有按照字母顺序排 而是按照添加顺序
//liuyan
//zhangmin
//zhangwuji
//linqingxia
//zhangmanyu
//wangzuxian
// Lambda表达式
// list.stream().sorted((s1,s2)->s1.length()-s2.length()).forEach(System.out::println);
* 按长度排序,长度相同 按照自然顺序排
list.stream().sorted((s1,s2)->{
int sum = s1.length()-s2.length();
int sum2 = sum == 0?s1.compareTo(s2):sum;
return sum2;
}).forEach(System.out::println);
// 输出结果:
//liuyan
//zhangmin
//zhangwuji
//linqingxia
//wangzuxian
//zhangmanyu
}
}
案例5:map mapToInt
package itiheima314.test5;
public class StreamDemo6 {
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<String>();
array.add("10");
array.add("20");
array.add("30");
array.add("40");
array.add("50");
* 需求:将集合中的字符串数据转化为整数之后在控制台输出
// array.stream().map(s -> Integer.parseInt(s)).forEach(System.out::println);
// array.stream().map(Integer::parseInt).forEach(System.out::println);
// 方法引用 分别是 类的方法(类名::静态方法)、对象的实例方法(对象的成员方法)
// array.stream().mapToInt(Integer::parseInt).forEach(System.out::println);
// mapToInt方法的返回值类型是 IntStream 其中有个int sum()方法 返回此流中元素的总和。
int result = array.stream().mapToInt(Integer::parseInt).sum();
System.out.println(result);
// 输出结果150
}
}
Stream流的常见终结操作方法forEach/count
方法名 | 说明 |
---|---|
viod forEach(Consumer action) | 对此流的每个元素执行操作 Consumer接口中的抽象方法 void accept(T t)对给定的参数执行此操作 |
long count() | 返回此流中的元素个数 |
案例: |
package itiheima314.test5;
public class StreamDemo7 {
public static void main(String[] args) {
ArrayList<String> list= new ArrayList<String>();
list.add("林俊杰");
list.add("张信哲");
list.add("王一博");
list.add("刘维");
list.add("张杰");
list.add("张艺兴");
* 需求1:把集合中的元素在控制台输出
// list.stream().forEach(System.out::println);
* 需求2:统计集合中有几个以张开头的元素,并把统计结果在控制台输出
long result = list.stream().filter(s -> s.startsWith("张")).count();
System.out.println(result);
// 输出结果是3
}
}
Stream流练习
需求:
有两个ArrayList集合,分别存储6名男演员和6名女演员名称,完成如下操作:
1 男演员只要名字为三个字的前三个人
Stream<String> manList = list.stream().filter(s -> s.length() == 3).limit(3);
2 女演员只要姓林的,并且不要第一个人
Stream<String> womanList = list.stream().filter(s ->s.startsWith("林")).skip(1);
3 把过滤后的男演员名字和女演员名字合并在一起
Stream<String> streamList = concat(manList,womanList);
4 把上一个步操作后的元素作为构造方法的参数创建演员对象,遍历数据
streamList.map(Actor::new).forEach(s -> System.out.println(s.getName()));
演员类Actor,有一个成员变量,一个带参构造方法,以为其对应的get/set方法
package itiheima314.test6;
public class StreamDemo {
public static void main(String[] args) {
// 创建集合
ArrayList<String> manList = new ArrayList<String>();
manList.add("周润发");
manList.add("成龙");
manList.add("刘德华");
manList.add("吴京");
manList.add("周星驰");
manList.add("李连杰");
ArrayList<String> womanList = new ArrayList<String>();
womanList.add("林心如");
womanList.add("张嘉倪");
womanList.add("林黛玉");
womanList.add("柳岩");
womanList.add("林志玲");
womanList.add("王祖贤");
// 1 男演员只要名字为三个字的前三个人
Stream<String> manStream = manList.stream().filter(s->s.length() ==3).limit(3);
// 2 女演员只要姓林的,并且不要第一个人
Stream<String> womanStream = womanList.stream().filter(s -> s.startsWith("林")).skip(1);
// 3 把过滤后的男演员名字和女演员名字合并在一起
Stream<String> conStream = Stream.concat(manStream, womanStream);
// 4 把上一个步操作后的元素作为构造方法的参数创建演员对象,遍历数据
// conStream.map(Actor::new).forEach(System.out::println);
// 引用方法是 引用构造器 = 类::构造方法
conStream.map(Actor::new).forEach(p-> System.out.println(p.getName()));
}
}
Stream流的收集操作
- 对数据使用Stream流的方式后,把流中的数据收集到集合中,收集方法是:R collect(Collector collector)
- 参数Collector 是一个接口interface,interface Collector< T,A,R >
- 工具类Collectors类实现了各种有用的还原操作的Collector
- Collector类提供了具体的收集方法:
方法名 | 说明 |
---|---|
public static < T > Collector toList() | 把元素收集到List集合中 |
public static < T > Collector toSet() | 把元素收集到Set集合中 |
public static < T > Collector toMap(Function keyMapper,Function valueMapper) | 把元素收集到Map集合中 toMap的参数必须是key |
案例:
package itiheima314;
public class test7 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("林俊杰");
list.add("张信哲");
list.add("王一博");
list.add("刘维");
* 需求1:得到名字为三个字的流
// Stream<String> stringList = list.stream().filter(s -> s.length() == 3);
* 需求2:把使用Stream流操作完毕的数据收集到List集合中
// List<String> names = stringList.collect(Collectors.toList());
// for(String name:names ){
// System.out.println(name);
// }
Set<Integer> set = new HashSet<Integer>();
set.add(10);
set.add(20);
set.add(30);
set.add(33);
set.add(35);
* 需求3:年龄大于25的流
// Stream<Integer> integerStream = set.stream().filter(a -> a > 25);
* 需求4:把使用Stream流操作完毕的数据收集到Set集合中
// Set<Integer> ages = integerStream.collect(Collectors.toSet());
// for(Integer age : ages){
// System.out.println(age);
// }
String[] strArray = {"林俊杰,30","张信哲,35","王一博,33","刘维,25"};
* 需求5:字符串中年龄大于28的流
Stream<String> ageStream = Stream.of(strArray).filter(s ->
Integer.parseInt(s.split(",")[1]) >28 );
* 需求6:把使用Stream流操作完毕的数据收集到Map集合中,并遍历
Map<String,Integer> map = ageStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1])));
Set<String> keySet = map.keySet();
for(String key:keySet){
Integer value = map.get(key);
System.out.println("姓名:" + value + ", " + "年龄:" + key);
}
}
}