目录
Stream流的三类方法
-
获取Stream流
-
创建一条流水线,并把数据放到流水线上准备进行操作
-
-
中间方法
-
流水线上的操作
-
一次操作完毕之后,还可以继续进行其他操作
-
-
终结方法
-
一个Stream流只能有一个终结方法【可以是forEach也开始收集方法】
-
是流水线上的最后一个操作
-
Stream流的获取方法
【只能在以下四种情况才能使用Stream流】
-
Collection体系集合【单列集合】
可以使用Collection接口中的默认方法stream()生成流, default Stream<E> stream()
-
Map体系集合【双列集合】
-
间接的生成流
-
可以先通过keySet或者entrySet获取一个Set集合,在获取Stream流 【对象名.stream】
-
-
数组
通过Arrays中的静态方法stream生成流 【Arrays.stream(数祖名)】
-
同种数据类型的多个数据
-
通过Stream接口的静态方法of(T... values)生成流【参数为可变参数】(Stream.of(1,2,3))
-
比如1,2,3,4,5.... ”aaa“,"bbb","ccc"..
-
/**
* Stream流的获取
单列集合 : 集合对象.stream();
双列集合 : 不能直接获取,需要间接获取
集合对象.keySet().stream();
集合对象.entrySet().stream();
数组 :
Arrays.stream(数组名);
同种数据类型的多个数据:
Stream.of(数据1,数据2,数据3......);
*/
public class MyStream2 {
public static void main(String[] args) {
//单列集合
//method1();
//双列集合
//method2();
//数组
//method3();
//同种数据类型的多个数据
//method4();
}
private static void method4() {
Stream.of(1,2,3,4,5,6,7,8).forEach(s-> System.out.println(s));
}
private static void method3() {
int [] arr = {1,2,3,4,5};
Arrays.stream(arr).forEach(s-> System.out.println(s));
}
private static void method2() {
HashMap<String,Integer> hm = new HashMap<>();
hm.put("zhangsan",23);
hm.put("lisi",24);
hm.put("wangwu",25);
hm.put("zhaoliu",26);
hm.put("qianqi",27);
//双列集合不能直接获取Stream流
//keySet
//先获取到所有的键
//再把这个Set集合中所有的键放到Stream流中
//hm.keySet().stream().forEach(s-> System.out.println(s));
//entrySet
//先获取到所有的键值对对象
//再把这个Set集合中所有的键值对对象放到Stream流中
hm.entrySet().stream().forEach(s-> System.out.println(s));
}
private static void method1() {
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
// Stream<String> stream = list.stream();
// stream.forEach(s-> System.out.println(s));
list.stream().forEach(s-> System.out.println(s));
}
}
Stream流中间操作方法
中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作
filter
Stream<T> filter(Predicate predicate) | 用于对流中的数据进行过滤 |
参数为Predicate接口,该接口只有一个text抽象方法
boolean text(T t):对给定的参数进行判断,返回一个布尔值【给数据做一个判断,如果为true则留下,为false则不要】
【调用filter方法时会利用其参数中的实现类的方法进行条件筛选】
/**
* Stream流的中间方法
需求:把姓张的留下
*/
public class MyStream3 {
public static void main(String[] args) {
// Stream<T> filter(Predicate predicate):过滤
// Predicate接口中的方法 boolean test(T t):对给定的参数进行判断,返回一个布尔值
ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张无忌");
list.add("张翠山");
list.add("王二麻子");
list.add("张良");
list.add("谢广坤");
/*filter方法获取流中的 每一个数据.
而test方法中的s,就依次表示流中的每一个数据.
我们只要在test方法中对s进行判断就可以了.
如果判断的结果为true,则当前的数据留下
如果判断的结果为false,则当前数据就不要.*/
普通写法:【使用匿名内部类写】
list.stream().filter(
new Predicate<String>() {
@Override
public boolean test(String s) {【参数s为流中的每一个数据,依次判断】
boolean result = s.startsWith("张");
return result;
}
}
).forEach(s-> System.out.println(s));
使用lamdba表达式简化书写:
【因为Predicate接口中只有一个抽象方法test
所以我们可以使用lambda表达式来简化】
list.stream().filter(
(String s)->{
boolean result = s.startsWith("张");
return result;
}
).forEach(s-> System.out.println(s));
进一步简化lamdba表达式:把两条语句转为一行,则return,:,大括号都可以省掉
list.stream().filter(s ->s.startsWith("张")).forEach(s-> System.out.println(s));
}
}
limit,skip,concat,distinct
方法名 | 说明 |
---|---|
Stream<T> limit(long maxSize) | 截取指定参数个数的数据【比如流中有十个数据,参数传3,截取前三个,后面的不要了】 |
Stream<T> skip(long n) | 跳过指定参数个数的数据,【比如流中有十个数据,参数传5,前5个不要了,剩余的留下】 |
static <T> Stream<T> concat(Stream a, Stream b) | 合并a和b两个流为一个流【把两个流的数据合并在一起】 |
Stream<T> distinct() | 去除流中重复的元素。依赖(hashCode和equals方法)【所以如果流中的数据是自定义对象student...,一定要重写方法】 |
public class MyStream4 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张无忌");
list.add("张翠山");
list.add("王二麻子");
list.add("张良");
list.add("谢广坤");
list.add("谢广坤");
list.add("谢广坤");
list.add("谢广坤");
list.add("谢广坤");
//method1(list);
//method2(list);
//method3();
//method4(list);
}
private static void method4(ArrayList<String> list) {
// Stream<T> distinct():去除流中重复的元素。依赖(hashCode和equals方法)
list.stream().distinct().forEach(s-> System.out.println(s));
【只有一个谢广坤,重复的去除掉了】
}
private static void method3() {
//static <T> Stream<T> concat(Stream a, Stream b):合并a和b两个流为一个流
【此方法为静态的,是Stream接口中的静态方法,调用时直接用Stream.concat】
ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张无忌");
list.add("张翠山");
list.add("王二麻子");
list.add("张良");
list.add("谢广坤");
ArrayList<String> list2 = new ArrayList<>();
list2.add("张三丰");
list2.add("张无忌");
list2.add("张翠山");
list2.add("王二麻子");
list2.add("张良");
list2.add("谢广坤");
一般书写:
Stream<String> stream1 = list.stream();
Stream<String> stream2 = list2.stream();
Stream<String> stream3 = Stream.concat(stream1, stream2);
stream3.forEach(s-> System.out.println(s));
简化书写:
Stream.concat(list.stream(),list2.stream()).forEach(s-> System.out.println(s));
}
private static void method2(ArrayList<String> list) {
// Stream<T> skip(long n):跳过指定参数个数的数据
list.stream().skip(2).forEach(s-> System.out.println(s));
【从第三个,张翠山开始,一直到最后一个】
}
private static void method1(ArrayList<String> list) {
// Stream<T> limit(long maxSize):截取指定参数个数的数据
list.stream().limit(2).forEach(s-> System.out.println(s));
【张三丰,张无忌】
}
}
Stream流终结操作方法 【forEach,count】
-
终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作
-
常见方法
方法名 说明 void forEach(Consumer action) 对此流的每个元素执行操作【获取流中的每一个元素,并对每一个元素执行操作,一般采取的是输出操作 】 long count() 返回此流中的元素个数
forEach方法中参数为Consumer接口
Consumer接口中的方法 只有一个抽象方法 void accept(T t):对给定的参数执行此操作
public class MyStream5 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三丰");
list.add("张无忌");
list.add("张翠山");
list.add("王二麻子");
list.add("张良");
list.add("谢广坤");
//method1(list);
long count():返回此流中的元素数
long count = list.stream().count();
System.out.println(count);
}
private static void method1(ArrayList<String> list) {
【
void forEach(Consumer action):对此流的每个元素执行操作Consumer接口中的方法accept
void accept(T t):对给定的参数(流中的每个数据)执行此操作
forEach方法的参数为接口,需传递一个实现类,举例采用匿名内部类实现
在forEach方法的底层,会循环获取到流中的每一个数据.
并把这些数据传递给accept方法,accept方法中的形参依次代表了流中的每一个数据
所以把对数据的处理写在accept方法中就可以了
循环调用accept方法,并把每一个数据传递给accept方法
s就依次表示了流中的每一个数据.
所以,我们只要在accept方法中,写上处理的业务逻辑就可以了.
】
list.stream().forEach(
new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
}
);
System.out.println("====================");
lambda表达式的简化格式
是因为Consumer接口中,只有一个accept方法
list.stream().forEach(
(String s)->{
System.out.println(s);
}
);
System.out.println("====================");
lambda表达式还是可以进一步简化的.
list.stream().forEach(s->System.out.println(s));
}
}
案例:
* Stream流的收集方法
* 练习:
* 定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10
* 将集合中的奇数删除,只保留偶数。
* 遍历集合得到2,4,6,8,10。
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
list.add(i);
}
// list.stream().filter(【filter对每个元素进行判断】
// (Integer i)->{ 【与集合中的泛型一致】
// return i % 2 == 0;
// }
// )
list.stream().filter(number -> number % 2 == 0).forEach(number -> System.out.print(number + " "));
System.out.println();
for (Integer integer : list) {
System.out.print(integer + " ");
}
}
执行结果:
2 4 6 8 10
1 2 3 4 5 6 7 8 9 10结论:在Stream流中无法直接修改集合,数组等数据源中的数据
Stream流中的数据修改的仅仅是封装在流中数据,把源数据复制一份封装到stream流对象中,对流进行过滤等操作不会影响源数据,只影响的是流中的数据
Stream流的收集操作Collect【终结方法】
-
对数据使用Stream流的方式操作完毕后,想把流中的数据收集起来,该怎么办?
-
可以把流中的数据收集到集合中
利用Stream流的收集方法【把流中数据存起来】
-
方法名 说明 R collect(Collector collector) 把结果收集到集合中
此方法的底层只管获取到流中的数据,不管创建容器,往容器中添加数据。
创建容器并添加是额外写代码给出的。这样的容器分为三种:toList,toSet,toMap方法
工具类Collectors提供了具体的收集方式:
方法名 | 说明 |
---|---|
public static <T> Collector toList() | 把元素收集到List集合中 |
public static <T> Collector toSet() | 把元素收集到Set集合中 |
public static Collector toMap(Function keyMapper,Function valueMapper) | 把元素收集到Map集合中 |
toList:底层创建一个list集合,并添加数据到list集合中
toSet,tooMap同理
这三个方法又是Collectors工具类的静态方法,可直接调用
收集到list,set中 :
public static void main(String[] args) {
ArrayList<Integer> list1= new ArrayList<>();
for (int i = 1; i <= 10; i++) {
list1.add(i);
}
//filter负责过滤数据的.
//collect只负责收集数据.
//获取流中剩余的数据,但是他不负责创建容器,也不负责把数据添加到容器中.
创建容器并添加数据是参数中的Collectors.toList()去操作
//Collectors.toList() : 在底层会创建一个List集合.并把所有的数据添加到List集合中.
collect(Collectors.toSet())原理:
collect方法获取流中数据,方法的形参起到把数据存入容器中并返回一个集合对象【底层是一个集合】
List<Integer> list = list1.stream().filter(number -> number % 2 == 0)
.collect(Collectors.toList());
System.out.println(list);
Set<Integer> set = list1.stream().filter(number -> number % 2 == 0)
.collect(Collectors.toSet());
System.out.println(set);
}
【set是不允许重复的】
执行结果:2,4,6,8,10
练习:收集到Map集合中
创建一个ArrayList集合,并添加以下字符串。字符串中前面是姓名,后面是年龄
"zhangsan,23"
"lisi,24"
"wangwu,25"
保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("zhangsan,23");
list.add("lisi,24");
list.add("wangwu,25");
【遍历】
/* list.stream().filter(
(String s)->{
String[] str = s.split(",");
int age=Integer.parseInt(str[1]);
return age > 24;
}
).forEach(s -> System.out.println(s));*/
//简化
list.stream().filter(
s->{
String[] str = s.split(",");
int age=Integer.parseInt(str[1]);
return age > 24;
}
).forEach(s -> System.out.println(s));
/* collect方法只能获取到流中剩余的每一个数据.
在底层不能创建容器,也不能把数据添加到容器当中
Collectors.toMap 创建一个map集合并将数据添加到集合当中
s 依次表示流中的每一个数据
第一个lambda表达式就是如何获取到Map中的键
第二个lambda表达式就是如何获取Map中的值
*/
【题意解题】
/* Map<String, Integer> map = list.stream().filter(
s -> {
String[] str = s.split(",");
int age = Integer.parseInt(str[1]);
return age > 24;
}
).collect(Collectors.toMap(
(String s) -> {
return s.split(",")[0];
},
(String s) -> {
return Integer.parseInt(s.split(",")[1]);
}
)
);*/
//简化lamdba
Map<String, Integer> map = list.stream().filter(
s -> {
String[] str = s.split(",");
int age = Integer.parseInt(str[1]);
return age > 24;
}
).collect(Collectors.toMap(
s -> s.split(",")[0],
s -> Integer.parseInt(s.split(",")[1])
)
);
System.out.println(map);
}
}
Stream流综合练习
案例需求
现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作
-
男演员只要名字为3个字的前三人
-
女演员只要姓林的,并且不要第一个
-
把过滤后的男演员姓名和女演员姓名合并到一起
-
把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法
演员类:
public class Actor { private String name; 标准javaBean get set 空参全参,tostring }
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("王祖贤");
//男演员要求
Stream<String> stream1 = manList.stream().filter(s -> s.length() == 3).limit(3);
//女演员要求
Stream<String> stream2 = womanList.stream().filter(s -> s.startsWith("林")).skip(2);
Stream.concat(stream1, stream2).forEach(name -> {
Actor actor = new Actor(name);
System.out.println(actor);
});
}
}