(1)Stream流的思想和获取Stream流
Stream流的思想
流水线思想,java.util.stream.Stream<T> 是函数式接口,Stream本身是接口。
Stream流的作用
结合了Lambda表达式,简化集合、数组的操作
Stream流的使用步骤:
先得到一条Stream流(流水线),并把数据放上去
利用Stream流中的API进行各种操作(
过滤,转换 -> 中间方法。 方法调用完毕之后,还可以调用其他方法
统计,打印 -> 终结方法) 最后一步,调用完毕之后,不能调用其他方法
所以:
先得到一条Stream流(流水线),并把数据放上去
使用中间方法对流水线上的数据进行操作
使用终结方法对流水线上的数据进行操作
获取Stream流的方式
单列集合 default Stream<E> stream() Collection中的默认方法
双列集合 无 无法直接使用stream流
数组 public static<T> Stream<T> stream(T[] array) Arrays工具类中的静态方法
一堆零散数据 public static<T> Stream<T> of(T…values) Stream接口中的静态方法
细节:
-
单列集合通过Collection中的默认方法stream()方法获取Stream流
-
双列集合无法直接获取,需通过keySet()方法或者entrySet()方法获取对应的单列Set集合,然后调用单列集合中的stream方法
-
数组可以通过Arrays工具类中的静态方法stream(T[] array)获取stream流
-
一堆零散的数据,注意这些数据的数据类型一致,可以通过Stream接口中的of方法获取stream流
这里Stream接口中静态方法of(T…values)方法的细节
//方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
//但是数组必须是引用数据类型的,如果传递基本数据类型,则会把整个数组当做一个元素,放到Stream当中,打印时会打印该数组的地址。
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Stream;
public class StreamDemo1 {
public static void main(String[] args) {
//单列集合通过stream()方法获取Stream流
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"a","b","c","d","e");
Stream<String> stream1 = list.stream();
stream1.forEach(s->System.out.println(s));
//双列集合无法直接获取
HashMap<String, Integer> hm = new HashMap<>();
hm.put("aaa",111);
hm.put("bbb",222);
hm.put("ccc",333);
hm.put("ddd",444);
//第一种获取stream流的方式Set<String>存储键的Set集合
hm.keySet().stream().forEach(key->System.out.println(key));
//第二种获取stream流的方式
hm.entrySet().stream().forEach(entry->System.out.println(entry.getKey()+":"+entry.getValue()));
// hm.entrySet().stream().forEach(new Consumer<Map.Entry<String, Integer>>() {
// @Override
// public void accept(Map.Entry<String, Integer> entry) {
// System.out.println(entry.getKey()+":"+entry.getValue());
// }
// });
//数组获取stream流的方式通过Arrays工具类中的静态方法stream(T[] array)方法获取
int[] arr1 = {1,2,3,4,5};
Arrays.stream(arr1).forEach(i->System.out.println(i));
String[] arr2 = {"a","b","c","d","e"};
Arrays.stream(arr2).forEach(s->System.out.println(s));
//一堆零散的数据获取stream流,只不过这些零散的数据类型相同,通过Stream接口中的静态方法of(T…values);获取
Stream.of(1,2,3,4).forEach(i->System.out.println(i));
Stream.of("a","b","c","d","e").forEach(s->System.out.println(s));
}
}
(2)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流只能使用一次(再次使用会出现IllegalStateException异常),建议使用链式编程
注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据
1、过滤
filter里面的参数 Predicate是一个函数式接口,所以要实现里面的public boolean test(T a) {}方法
例 public boolean test(String s){return s.startsWith("张");}
//如果返回值为true,表示当前数据留下
//如果返回值为false,表示当前数据舍弃不要
2、元素去重
distinct()底层是依赖HashSet,所以依赖hashCode和equals方法,如果泛型类型是自定义对象,那么需要在自定义类中进行重写方法。
3、转换流中的数据类型
map参数类型为函数式接口类型(Function),需要实现类实现该接口,然后通过new 这个实现类传递参数,但是JDK8以后的匿名内部类实现了这一复杂过程的简化,之后的Lambda表达式再次简化匿名内部类的书写
例://Function函数式接口,泛型约束的类型,第一个类型:流中原本的数据类型,第二个类型:要转成之后的类型 //apply返回值:表示转换之后的数据 //当map方法执行完毕之后,流上的数据就变成了整数
list4.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
String[] arr = s.split("-");
String ageString = arr[1];
int age = Integer.parseInt(ageString);
return age;
}
}).forEach(age-> System.out.println(age));
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class StreamDemo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"刘备","孙尚香","孙权","孙策","孙仲谋","孙膑","马超");
//filter过滤,参数为函数式接口对象,返回值为true保留,返回值为false不保留
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("孙");
}
}).forEach(s->System.out.println(s));
Stream<String> stream1=list.stream().filter(s->s.startsWith("孙"));
Stream<String> stream2=stream1.filter(s->s.length() == 3);
stream2.forEach(s->System.out.println(s));
System.out.println("++++++++++++++++++++++++++++++++++++++++++++");
//Stream<String> stream3 = stream1.filter(s->s.length()==3);
list.stream().filter(s->s.startsWith("孙")).filter(s->s.length() == 3).forEach(s->System.out.println(s));
//limit(int n)获取流中前n个元素
list.stream().limit(3).forEach(s->System.out.println(s));
System.out.println("+++++++++++++++++++++++++++++++++");
//skip(int n)跳过lq中前n个元素
list.stream().skip(4).forEach(s->System.out.println(s));
System.out.println("+++++++++++++++++++++++++++++++++++");
list.stream().limit(5).skip(2).forEach(s->System.out.println(s));
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1,"孙尚香","孙权","孙策","孙仲谋","孙膑","孙权","孙尚香");
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2,"刘备","张飞","关羽");
//distinct 元素去重,依赖(hashCode和equals方法);
list1.stream().distinct().forEach(s->System.out.println(s));
System.out.println("+++++++++++++++++++++++++++++");
//Stream接口中的静态方法concat,合并两个stream流
Stream.concat(list1.stream(),list2.stream()).forEach(s->System.out.println(s));
ArrayList<String> list4 = new ArrayList<>();
Collections.addAll(list4,"刘备-32","孙尚香-18","孙权-19","孙策-28","孙仲谋-47","孙膑-81","马超-24");
//Function函数式接口,泛型约束的类型,第一个类型:流中原本的数据类型,
第二个类型:要转成之后的类型
//apply返回值:表示转换之后的数据
//当map方法执行完毕之后,流上的数据就变成了整数
list4.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
String[] arr = s.split("-");
String ageString = arr[1];
int age = Integer.parseInt(ageString);
return age;
}
}).forEach(age-> System.out.println(age));
}
}
(3)Stream流的终结方法
终结方法
void forEach(Consumer action) 遍历
Long count() 统计
toArray() 收集流中的数据,放到数组中
collect(Collector collector) 收集流中的数据,放到集合中
——1、收集流中的数据,放到数组中
String[] arr = list.stream().toArray(new IntFunction<String[]>() { @Override public String[] apply(int value) { return new String[value]; } }); System.out.println(Arrays.toString(arr));
//有参 //IntFunction的泛型:具体类型的数组 //apply的形参:流中数据的个数,要跟数组的长度保持一致 //apply的返回值:具体类型的数组 //方法体:就是创建数组 //toArray方法的参数的作用:负责创建一个指定类型的数组 //toArray方法的底层,会依次得到流里面的每个数据,并把数据放到数组当中 //toArray方法的返回值:是一个装着流里面所有数据的数组
toArray()方法引用:toArray(Integer[] :: new);
方法引用:引用数组的构造方法
格式:数据类型[]::new
范例:int[]::new
引用数组的构造方法就是为了创建数组。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.IntFunction;
public class StreamDemo3 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"刘备","孙尚香","孙权","孙策","孙仲谋","孙膑","马超");
list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
//统计 long count()
long count=list.stream().count();
System.out.println(count);
//toArray() 收集流里面的数据,把收集到的数据放到数组中
//无参
Object[] arr1 = list.stream().toArray();
System.out.println(Arrays.toString(arr1));
//有参
//IntFunction的泛型:具体类型的数组
//apply的形参:流中数据的个数,要跟数组的长度保持一致
//apply的返回值:具体类型的数组
//方法体:就是创建数组
//toArray方法的参数的作用:负责创建一个指定类型的数组
//toArray方法的底层,会依次得到流里面的每个数据,并把数据放到数组当中
//toArray方法的返回值:是一个装着流里面所有数据的数组
String[] arr = list.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
System.out.println(Arrays.toString(arr));
String[] arr2 = list.stream().toArray( value-> new String[value]);
System.out.println(Arrays.toString(arr2));
}
}
——2、收集流中的数据,放到集合中
collect(Collector collector) 收集流中的数据,放到集合中(List Set Map)
Collectors 是 java.util.stream 包下的一个工具类,全称java.util.stream.Collectors。
它是一个工具类,里面全是静态方法,专门用来配合 Stream.collect() 做收集操作。
常用的静态方法有:
-
Collectors.toList():收集为 List
-
Collectors.toSet():收集为 Set
-
Collectors.toMap():收集为 Map
toMap的两个参数为Function函数式接口对象参数一表示键的生成规则,参数二表示值的生成规则,具体看下面的代码及详解
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class StreamDemo4 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,
"张无忌-男-15",
"周芷若-女-14",
"赵敏-女-13",
"张强-男-20",
"张三丰-男-100",
"张翠山-男-40",
"张良-男-35",
"王二麻子-男-37",
"谢广坤-男-41"
);
//收集List集合道中,把所有的男性收集起来。
List<String> newList1 = list.stream().filter(new Predicate<String>(){
@Override
public boolean test(String s) {
return "男".equals(s.split("-")[1]);
}
}).collect(Collectors.toList());
System.out.println(newList1);
List<String> newList11 = list.stream()
.filter( s-> "男".equals(s.split("-")[1]))
.collect(Collectors.toList());
//收集到Set集合当中,把所有男生
Set<String> newList2 = list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return "男".equals(s.split("-")[1]);
}
}).collect(Collectors.toSet());
System.out.println(newList2);
Set<String> newList22 = list.stream()
.filter( s-> "男".equals(s.split("-")[1]))
.collect(Collectors.toSet());
//收集到Map集合中,把所有的男生收集起来,键:姓名,值:年龄
/*toMap : 参数一表示键的生成规则
参数二表示值的生成规则
参数一:
Function泛型一:表示流中每一个数据的类型
泛型二:表示Map集合中键的数据类型
方法apply形参:依次表示流里面的每一个数据
方法体:生成键的代码
返回值:已经生成的键
参数二:
Function泛型一:表示流中的每一个数据的类型
泛型二:表示Map集合中值的数据类型
方法apply形参:依次表示流里面的每一个数据
方法体:生成值的代码
返回值:已经生成的值
*/
Map<String,Integer> m = list.stream().filter(s->"男".equals(s.split("-")[1]))
.collect(Collectors.toMap(new Function<String,String>() {
@Override
public String apply(String s) {
return s.split("-")[0];
}
}, new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s.split("-")[2]);
}
}
));
System.out.println(m);
Map<String,Integer> m1 = list.stream()
.filter(s->"男".equals(s.split("-")[1]))
.collect(Collectors.toMap(
s-> s.split("-")[0],
s-> Integer.parseInt(s.split("-")[2])));
}
}
(4)Stream流总结

(5)Stream流练习
——1、数字的过滤
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;
public class StreamDemo5{
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list,1,2,3,4,5,6,7,8,9,10);
list.stream().filter(new Predicate<Integer>() {
@Override
public boolean test(Integer n) {
return n % 2 == 0 ? false : true;
}
}).forEach(i -> System.out.println(i));
list.stream()
.filter(n-> n % 2 == 0 ? false : true)
.forEach(i -> System.out.println(i));
}
}
——2、字符串过滤并收集
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class StreamDemo6 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"孙权,23","孙尚香,19","孙膑,81","孙策,35","孙仲谋,51","马超,23","周瑜,32","瑶,18");
Map<String, Integer> map = list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
String ageStr = s.split(",")[1];
Integer age = Integer.parseInt(ageStr);
return age >=24;
}
}).collect(Collectors.toMap(new Function<String, String>() {
@Override
public String apply(String s) {
return s.split(",")[0];
}
},new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s.split(",")[1]);
}
}));
System.out.println(map);
Map<String, Integer> m = list.stream()
.filter( s-> {return Integer.parseInt(s.split(",")[1]) >=24; })
.collect(Collectors.toMap(s-> s.split(",")[0],
s-> Integer.parseInt(s.split(",")[1])));
}
}
——3、自定义对象的过滤收集

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamDemo7 {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1,"马超-23","赵子龙-29","关羽-40","张飞-38","曹操-43","牢大-35");
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2,"孙尚香-19","瑶-16","孙美姬-23","王昭君-25","杨玉环-31","孙樱-20");
Stream<String> stream1 = list1.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.split("-")[0].length()==2;
}
}).limit(2);
Stream<String> stream2 = list2.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.split("-")[0].startsWith("孙");
}
}).skip(1);
List<Student> list = Stream.concat(stream1,stream2).map(new Function<String, Student>() {
@Override
public Student apply(String s) {
Student stu = new Student();
stu.setName(s.split("-")[0]);
stu.setAge(Integer.parseInt(s.split("-")[1]));
return stu;
}
}).collect(Collectors.toList());
System.out.println(list);
}
}
class Student {
String name;
int age;
public Student() {}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}


