案例需求
按照下面的要求完成集合的创建和遍历
原始方式示例代码
public static void main(String[] args) {
ArrayList<String> list1=new ArrayList<>();
initList(list1);
System.out.println(list1);
ArrayList<String> list2=new ArrayList<>();
for (String s : list1) {
if(s.startsWith("云")) list2.add(s);
}
System.out.println(list2);
ArrayList<String> list3=new ArrayList<>();
for (String s : list2) {
if(s.length()==3) list3.add(s);
}
System.out.println(list3);
}
public static void initList(ArrayList<String> list){
String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
for (String s : ss) list.add(s);
}
public static void main(String[] args) {
ArrayList<String> list1=new ArrayList<>();
initList(list1);
System.out.println(list1);
//stream流,借助lambda表达式,非常简单
list1.stream().filter(s -> s.startsWith("云"))
.filter(s -> s.length()==3)
.forEach(s -> System.out.print(s+" "));
}
public static void initList(ArrayList<String> list){
String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
for (String s : ss) list.add(s);
}
Stream流的好处
逐一打印
Stream流的三类方法
生成Stream流的方式
Collection体系集合
使用默认方法stream()生成流, default Stream< E> stream()
Map体系集合
把Map转成Set集合(keySet或entrySet),间接的生成流
数组
通过Arrays中的静态方法stream生成流
同种数据类型的多个数据
通过Stream接口的静态方法of(T… values)生成流
代码演示
获取stream流: Stream< String> stream = list.stream();
操作stream流: stream.forEach(s -> System.out.print(s+" "));
public static void main(String[] args) {
//单列集合
ArrayList<String> list = new ArrayList<>();
initList(list);
System.out.println(list);
//单列集合生成流
Stream<String> stream = list.stream();
//查看流里有啥
stream.forEach(s -> System.out.print(s+" "));//”aaa bbb ccc “
System.out.println();
//一般流都是直接写再一起的
list.stream().forEach(s -> System.out.print(s+" "));//”aaa bbb ccc “
}
public static void initList(ArrayList<String> list){
String[] ss={"aaa","bbb","ccc"};
for (String s : ss) list.add(s);
}
先获取keySet或者entrySet,再获取流
map.keySet().stream() 或者 map.entrySet().stream()
public static void main(String[] args) {
//双列集合
HashMap<String,Integer> hm=new HashMap<>();
initList(hm);
//System.out.println(hm);
//开始先获取stream流
//注意:双列集合不能直接获取stream流
//1.keySet
//1.1先获取keySet(所有的键)
//1.2再把这个Set集合中所有的键放到Stream流中
hm.keySet().stream().forEach(s -> System.out.print(s+" "));
//上行输出:lisi zhaoliu zhangsan wangwu tianqi
System.out.println("\n===========================================");
//2.entrySet
//2.1先获取所有的键值对对象(entrySet)
//2.2再把这个Set集合中所有键值对对象放到Stream流中
hm.entrySet().stream().forEach(s ->System.out.println(s));
}
public static void initList(HashMap<String,Integer> map){
String[] name={"zhangsan","lisi","wangwu","zhaoliu","tianqi"};
Integer[] age={23,24,25,26,27};
for(int i=0;i<name.length;i++) map.put(name[i],age[i]);
}
public static void main(String[] args) {
//数组-》流
int[] arr={1,2,3,4,5};
Arrays.stream(arr).forEach(s->System.out.print(s+" "));//"1 2 3 4 5"
//拓展
System.out.println();
System.out.println(Arrays.toString(arr));//数组输出
System.out.println(Arrays.stream(arr).max().getAsInt());//流求 数组最大值 5
System.out.println(Arrays.stream(arr).min().getAsInt());//流求 数组最小值 1
System.out.println(Arrays.stream(arr).average().getAsDouble());//流求 数组平均 3.0
System.out.println(Arrays.stream(arr).count());//流求 数组长度 5
System.out.println(Arrays.stream(arr).sum());//流求 数组求和 15
}
public static void main(String[] args) {
//同种数据类型多个数据->流水线
Stream.of(1,4,6,7,8,2,3,5,10,9).forEach(s->System.out.print(s+" "));
System.out.println();
//DIY应用 过滤掉奇数
Stream.of(1,4,6,7,8,2,3,5,10,9).filter(i->i%2!=0)
.forEach(i->System.out.print(i+" "));
}
单列集合 : 集合对象.stream();
双列集合 : 不能直接获取,需要间接获取
集合对象.keySet().stream();
集合对象.entrySet().stream();
数组 :
Arrays.stream(数组名);
同种数据类型的多个数据:
Stream.of(数据1,数据2,数据3......);
概念
中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作
常见方法
方法名 | 说明 |
---|---|
Stream< T> filter(Predicate predicate) | 用于对流中的数据进行过滤 |
Stream< T> limit(long maxSize) | 返回此流中的元素组成的流,截取前指定参数个数的数据 |
Stream< T> skip(long n) | 跳过前指定参数个数的数据,返回由该流的剩余元素组成的流 |
static < T> Stream< T> concat(Stream a, Stream b) | 合并a和b两个流为一个流 |
Stream< T> distinct() | 返回由该流的不同元素(根据hashCode和equals方法 )组成的流 |
public static void main(String[] args) {
ArrayList<String> list1=new ArrayList<>();
initList(list1);
System.out.println(list1);
//留下"云"开头的 过滤掉其他的
//filter方法获取流中的每个数据
//而test方法中的s,就依次表示流中的每一个数据
//则只需在test方法中s进行判断就行了:true该数据留校 false该数据丢弃
System.out.println("==============匿名内部类=============");
list1.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("云");
}
}).forEach(s->System.out.print(s+" "));
System.out.println("\n==============lambda表达式=============");
//因为Predicate接口中只有一个★抽象方法Test★,因此可以用lambda表达式简化
//接下来,再用lambda表达式简化一下就ok了
list1.stream().filter((String s)->{
return s.startsWith("云");
}).forEach(s->System.out.print(s+" "));
System.out.println("\n==============lambda表达式省略写法=============");
//参数只有一个: 可以省略 类型与括号()
//方法体语句只有一条: return可以省略 ";"可以省略
list1.stream().filter(s->s.startsWith("云")).forEach(s->System.out.print(s+" "));
}
public static void initList(ArrayList<String> list){
String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
for (String s : ss) list.add(s);
}
Stream< T> limit(long maxSize); || eg:limit(3) 截取前3个数据 Stream< T>
Stream< T> skip(long n) || eg:skip(3) 前3个数据不要(剩余的都留下)
public static void main(String[] args) {
ArrayList<String> list1=new ArrayList<>();
initList(list1);
System.out.println(list1);
//Stream< T> limit(long maxSize); eg:limit(3) 截取前3个数据
System.out.println("==============.stream().limit(2)================");
list1.stream().limit(2).forEach(s -> System.out.print(s+" "));//云天河 韩菱纱
//Stream< T> skip(long n) eg:skip(3) 前3个数据不要(剩余的都留下)
System.out.println("\n==============.stream().skip(2)================");
list1.stream().skip(2).forEach(s -> System.out.print(s+" "));
}
public static void initList(ArrayList<String> list){
String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
for (String s : ss) list.add(s);
}
static < T> Stream< T> concat(Stream a, Stream b) | 合并a和b两个流为一个流
Stream< T> distinct() 流中数据去重(根据hashCode和equals方法 )
public static void main(String[] args) {
ArrayList<String> list1=new ArrayList<>();
ArrayList<String> list2=new ArrayList<>();
initList(list1);initList(list2);
System.out.println(list1);
System.out.println(list2);
//static < T> Stream< T> concat(Stream a, Stream b) | 合并a和b两个流为一个流
System.out.println("==================合并====================");
Stream<String> stream = Stream.concat(list1.stream(), list2.stream());
stream.forEach(s -> System.out.print(s+" "));
//【stream被终止方法操作过一次就会终止,不能再被操作了】
//Stream< T> distinct() 流中数据去重(根据hashCode和equals方法 )
System.out.println("\n==================去重====================");
//上面的stream流水线已经结束了 不能再使用了 (应该forEach是终止方法)
Stream<String> stream2 = Stream.concat(list1.stream(), list2.stream());
stream2.distinct().forEach(s -> System.out.print(s+" "));
}
public static void initList(ArrayList<String> list){
String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
for (String s : ss) list.add(s);
}
概念(★)
终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作
常见方法
方法名 | 说明 |
---|---|
void forEach(Consumer action) | 对此流的每个元素执行操作 |
long count() | 返回此流中的元素数 |
public static void main(String[] args) {
ArrayList<String> list1=new ArrayList<>();
initList(list1);
System.out.println(list1);
//终结方法1:forEach 【终结方法执行后,本次流水线结束。不能再操作此流水线了】
System.out.println("=============forEach:匿名内部类============");
//在forEach方法的底层,会循环获取到流中的每一个数据.
//并循环调用accept方法,并把每一个数据传递给accept方法
//s就依次表示了流中的每一个数据.
//所以,我们只要在accept方法中,写上处理的业务逻辑就可以了.
list1.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.print(s+" ");
}
});
//Consumer接口内只有一个抽象方法,可以用lambda表达式
System.out.println("\n=============forEach:lambda表达式============");
list1.stream().forEach((String s)->{
System.out.print(s+" ");
});
//一个参数:省略 类型+小括号
//一条语句:省略 return、分号、大括号
System.out.println("\n=============forEach:lambda表达式简化============");
list1.stream().forEach(s->System.out.print(s+" "));
}
public static void initList(ArrayList<String> list){
String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
for (String s : ss) list.add(s);
}
public static void main(String[] args) {
ArrayList<String> list1=new ArrayList<>();
initList(list1);
System.out.println(list1);
//终结方法2:count(): 统计流中元素个数【终结方法执行后,本次流水线结束。不能再操作此流水线了】
long count = list1.stream().count();
System.out.println(count);//9
}
public static void initList(ArrayList<String> list){
String[] ss={"云天河","韩菱纱","慕容紫英","柳梦璃","玄霄","夙玉","云天青","云来石","云叔"};
for (String s : ss) list.add(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);//快捷写法: 10.fori
System.out.println("=============用流去重后输出流=============");
list.stream().filter(i -> i%2==0).forEach(i->System.out.print(i+" "));
System.out.println("\n=============输出原集合=============");
System.out.println(list);//list完好无损: 说明list.stream().filter并没有直接修改list集合的数据
}
stream流无法直接修改集合中元素,有修改需求时咋办呢?有专门的收集API
概念
对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中
常用方法(collect也是终结方法)
方法名 | 说明 |
---|---|
R collect(Collector collector) | 把结果收集到集合中 |
工具类Collectors提供了具体的收集方式
方法名 | 说明 |
---|---|
public static Collector toList() | 把元素收集到List集合中 |
public static Collector toSet() | 把元素收集到Set集合中 |
public static Collector toMap(Function keyMapper,Function valueMapper) | 把元素收集到Map集合中 |
案例: 只保留list集合中的偶数(删除所有奇数)
public static void main(String[] args) {
ArrayList<Integer> list1=new ArrayList<>();
for (int i = 1; i <= 10; i++) list1.add(i);//快捷写法: 10.fori
list1.add(10);list1.add(10);list1.add(10);list1.add(10);list1.add(10);
//1.收集到list中
//filter负责过滤数据的.
//collect负责收集数据.
//获取流中剩余的数据,但是他不负责创建容器,也不负责把数据添加到容器中.
//Collectors.toList() : 在底层会创建一个List集合.并把所有的数据添加到List集合中.
List<Integer> list = list1.stream().filter(i -> i % 2 == 0)
.collect(Collectors.toList());
System.out.println(list);//[2, 4, 6, 8, 10, 10, 10, 10, 10, 10]
//2.收集到Set中
Set<Integer> set = list1.stream().filter(i -> i % 2 == 0)
.collect(Collectors.toSet());
System.out.println(set);[2, 4, 6, 8]
}
案例:
public static void main(String[] args) {
ArrayList<String > list=new ArrayList<>();
list.add("zhangsan,23");
list.add("lisi,24");
list.add("wangwu,25");
//collect和forEach都是终结方法 只能有一个
/*list.stream().filter(s -> Integer.valueOf(s.split(",")[1])>=24)
.forEach(s -> System.out.println(s));*/
Map<String, Integer> map = list.stream().filter(
s -> {
String[] split = s.split(",");
int age = Integer.parseInt(split[1]);
return age >= 24;
}
//collect方法只能获取到流中剩余的每一个数据.
//在底层不能创建容器,也不能把数据添加到容器当中
//Collectors.toMap 创建一个map集合并将数据添加到集合当中
// s 依次表示流中的每一个数据
//第一个lambda表达式就是如何获取到Map中的键
//第二个lambda表达式就是如何获取Map中的值
).collect(Collectors.toMap(
(String s) ->{
return s.split(",")[0];
} ,
(String s) -> {
return Integer.parseInt(s.split(",")[1]);
}
));
System.out.println(map);//{lisi=24, wangwu=25}
//简化写法
Map<String, Integer> map2 = list.stream().filter(s -> Integer.valueOf(s.split(",")[1]) >= 24)
.collect(Collectors.toMap( s->s.split(",")[0] , s->Integer.valueOf(s.split(",")[1]) ));
System.out.println(map2);//{lisi=24, wangwu=25}
}
案例需求
现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作
演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法
代码实现
演员类
public class Actor {
private String name;
//全参、空参、get/set、toString
}
测试类:
public static void main(String[] args) {
ArrayList<String> manList = new ArrayList<>();
manList.add("张国立"); manList.add("张晋"); manList.add("刘烨");
manList.add("郑伊健"); manList.add("徐峥"); manList.add("王宝强");
ArrayList<String> womanList = new ArrayList<>();
womanList.add("刘亦菲"); womanList.add("杨紫"); womanList.add("关晓彤");
womanList.add("张天爱"); womanList.add("杨幂"); womanList.add("赵丽颖");
//男演员只要名字为3个字的前两人
Stream<String> stream1 = manList.stream().filter(s -> s.length() == 3).limit(2);
//女演员只要姓林的,并且不要第一个
Stream<String> stream2 = womanList.stream().filter(s -> s.startsWith("杨")).skip(1);
//合并 后封装从对象再打印出对象
Stream.concat(stream1,stream2).forEach(s -> {
Actor actor = new Actor(s);
System.out.println(actor);
});
}