不可变集合 Stream流
不可变集合
如果牌盒里的牌固定为那54张,不能被改变
- 如出牌规则不可变
- 通过of方法获取不可变集合
不可变集合是java9提出的新特性
在List Map Set中都定义了许多重载的静态of方法,用于获取指定内容的不可变的集合,如下面是List中定义的of方法
这些方法将直接返回List Map Set的集合,就相当于已经通过多态得到了List Map Set这写接口的对象,但是在调用时也只能调用在子类中覆写自接口的抽象方法
java提供了指定任意个集合内容的of方法,因为不支持添加操作,所有这样设置
List的不可变集合演示
//演示List的不可变集合
import java.util.*;
public class Main{
public static void main(String[]args){
/*
不可变集合特点:
一旦集合被创建 其集合的内容只能支持查询操作
不能进行添加(增)删除 修改*/
//1.创建List不可变集合
List<String> list= List.of("张三","李四","王五","赵六");//添加3个对象
//2.查询每一个成员:通过索引得到每一个元素
System.out.println(list.get(0));
System.out.println(list.get(1));
System.out.println(list.get(2));
System.out.println(list.get(3));
System.out.println("-----------------------------------------------------");
//3.遍历集合
//3.1用迭代器遍历
Iterator<String> it =list.iterator();//获取迭代器对象
while(it.hasNext()){
String a = it.next();//获取元素并向后移动指针
System.out.println(a);
}
System.out.println("-------------------------------------------------");
//4.用增强for遍历集合
for(String c:list){
System.out.println(c);
}
//5.测试不能进行增删改
//5.1增
// list.add("hello");//向集合中添加:将会抛出异常
//5.2删
//list.remove("张三");//删除集合中的指定元素:将会抛出异常
//5.3修改
//list.set(0,"hello");//将指定索引处的元素修改成指定的元素:将会抛出异常
}
}
Set集合的可变集合(和List类似)
//演示Set的不可变集合
import java.util.*;
public class Main{
public static void main(String[]args){
/*
不可变集合特点:
一旦集合被创建 其集合的内容只能支持查询操作
不能进行添加(增)删除 修改*/
//1.创建Set不可变集合
Set<String> set= Set.of("张三","李四","王五","赵六");//添加3个对象
//3.遍历集合
//3.1用迭代器遍历
Iterator<String> it =set.iterator();//获取迭代器对象
while(it.hasNext()){
String a = it.next();//获取元素并向后移动指针
System.out.println(a);
}
System.out.println("-------------------------------------------------");
//4.用增强for遍历集合
for(String c:set){
System.out.println(c);
}
//测试不能进行增删该操作
//1.增
//set.add("hello");//将会抛出异常
//2.删
// set.remove("张三");//将会抛出异常
//3.改:Set中没有修改操作
set.clear();//清空也会报错
}
}
Set不可变集合的细节:当我们要获取一个不可变的Set集合时,of方法里面的参数(即不可变集合的内容一定要保证其唯一性)
Map集合的不可变集合
Map不可变集合的细节:1.of方法的参数(即集合的内容)不能重复 2.在Map中的of方法没有带有可变参数的of方法,Map集合的of方法最多只能传递20个参数,即只能传递10对键值对
对于Map集合的of方法,可以用来创建0-10对键值对的不可变的Map集合,捕捉和Set和List类似,这里不再演示
为什么Map集合没有设置可变参数
Map集合是双列集合和前面的单列集合不一样,它的每个成员是由2个对象构成,当我们的of方法得需要可以添加任意个的成员,而一个键对应一个值,这说明键需要可以添加任意个,值也可以添加任意个,则需要将of方法设置成以下的样式
public static <K,V> Map<K,V> of(K... k1,V... v1){
}
但是这违反了可变参数的规定,即函数的可变参数只能有一个并且放在最后
如果我们需要创建的键值对对象超过10该怎么办?
public static <K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>... entries)
Map集合的ofEntries方法可以返回Map的不可变集合,主要是任意个参数都可以
此时的改进思想是将键和值包装成一个集合,这样就只用写一个参数即可,ofEntries函数就是利用了这一点
public static <K,V> Map<K,V> copyOf(Map<? extends K,? extends V> map)(jdk10新特性)
该方法的参数直接用Map即可(或者是其子类)
可以使用可变参数传递任意参数演示
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Main {
public static void main(String[] args) {
//测试Map的不可变参数(特指可以创建任意个成员变量的函数)
//1.ofEntries函数 static<K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>...entries)
//该方法的参数是Entry集合
HashMap<String,String> hm = new HashMap<>();//创建一个map集合
//在hm集合中添加任意个参数
hm.put("张三","北京");
hm.put("李四","南京");
hm.put("王五","武汉");
hm.put("赵六","天津");
hm.put("郝建","上海");
Set<Map.Entry<String, String>> entries = hm.entrySet();
//方法一
//2.将entries变成一个数组
Map.Entry[]arr1 = new Map.Entry[0];//创建数组用于储存集合里的内容(这里直接写0底层会重新创建数组)
Map.Entry[]arr2 = entries.toArray(arr1);//现在arr2里面储存的就是所有的Entry对象
/*
toArray函数的细节(将集合变成数组):
toArray函数在底层会比较集合的长度和数组(用来装集合的数组)长度的大小
*如果集合长度>数组长度:数据在数组中放不下,此时会根据实际数据的长度,重新创建数组
*如果集合长度<=数组长度:数据在数组中放的下,此时不会创建新的数组,而是直接使用
所有用来存放数据的数组长度直接写0即可
*/
Map<String,String> map= Map.ofEntries(arr2);
//ofEntries的参数是Entry集合的可变集合,在传参的时候可以传递任意个Entry集合,由于可变参数的底层是一个数组,所有
//我们在传递参数是时候也可以传递一个对象数组(对象为Entry类型)
//2.上面写的有点复杂,我们利用链式编程简化代码
//方法一(优化版)
Map<String,String> map1= Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));
//用copyOf(方法二)
Map<String,String> map2=Map.copyOf(hm);//该方法返回Map的不可变集合
System.out.println(map2);
}
}
Stream流
体验Stream流的作用
package com.an.a;
import java.util.ArrayList;
//测试Stream流的使用
public class StreamTest {
public static void main(String[] args) {
/*
创建集合添加元素,完成以下需求:
1.把所用张开头的元素储存到新的集合中
2.把所有张开头的,长度为3的元素再储存到新的集合中
3.遍历打印结果
*/
ArrayList<String> list1 = new ArrayList<>();
list1.add("张无忌");
list1.add("赵敏");
list1.add("周芷若");
list1.add("张强");
list1.add("张三丰");
//1.把所有张开头的元素添加到新的集合中
//2.把所有的张开头的并且长度为3的元素再次储存到新的集合中(这里也可以分开遍历,只需要遍历list1即可)
ArrayList<String> list2 = new ArrayList<>();
ArrayList<String> list3 = new ArrayList<>();
for (String name : list1) {
if(name.startsWith("张")){
list2.add(name);
if(name.length()==3){
list3.add(name);
}
}
}
//我们可以发现上面的代码太长了,而利用Stream流可以让代码跟简介(结合Lamdba表达式)
list1.stream().filter(name->name.startsWith("张")).filter(name->name.length()==3).forEach(name-> System.out.println(name));
//上面的代码直接可以实现对张开头并且长度为3的过滤
}
}
Stream流的思想和获取Stream流
可以将流想象成工厂的流水线
当检查瓶子不合格就和被扔掉,符合规定将进行下面的步骤
流的思想和上面工厂相似,将数据一步步过滤,然后留下我们需要的数据
好像Lamdba表达式是基础,故先学习
注意点:1.双列集合不能直接使用Stream流进行操作,需要使用KeySet或entrySet转化成单列集合2.对于对零散数据的操作要求这些数据的类型相同
1.获取单列集合的Stream
package com.an.a;
import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Stream;
//测试各种数据获取Stream
public class StreamTest1 {
/*
单列集合 default Stream<E> stream() Collection中的默认方法
双列集合 无 无法直接获取Stream流
数组 public static <T> Stream(T[]arry) Arrays类中的静态方法
一堆零散数据 public static <T>Stream<T>of(T...values)Stream接口中的静态方法
*/
public static void main(String[] args) {
//1.单列集合获取Stream
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"aaa","bbb","ccc","ddd");//批量添加数据
//获取Stream:获取到一条流水线并把数据放到上面
//遍历数据
//Stream<String> stream = list.stream();
//stream.forEach( s-> System.out.println(s));
//链式编程简化代码
list.stream().forEach(s-> System.out.println(s));
}
}
对于单列集合的Set系列,和上面操作一样不再演示
2.获取双列集合的Stream
package com.an.a;
import java.util.*;
import java.util.stream.Stream;
//测试各种数据获取Stream
public class StreamTest1 {
/*
单列集合 default Stream<E> stream() Collection中的默认方法
双列集合 无 无法直接获取Stream流
数组 public static <T> Stream(T[]arry) Arrays类中的静态方法
一堆零散数据 public static <T>Stream<T>of(T...values)Stream接口中的静态方法
*/
public static void main(String[] args) {
//2.获取双列集合的Stream
HashMap<String,Integer>hm = new HashMap<>();
hm.put("aaa",111);
hm.put("bbb",222);
hm.put("ccc",333);
hm.put("ddd",444);
//Map集合不能直接获取Stream要将其转化为Set集合
//1.第一种方式:将所有键转化为Set
// Set<String> keys = hm.keySet();//将所有的键转化为Set集合
//keys.stream().forEach( s-> System.out.println(s));
//链式编程简化
hm.keySet().stream().forEach(s-> System.out.println(s));
//2.第二种方法:将所有的键值对转化为Set
Set<Map.Entry<String, Integer>> entries = hm.entrySet();
entries.stream().forEach(s-> System.out.println(s));
//链式编程简化
hm.entrySet().stream().forEach(s-> System.out.println(s));
}
}
3.获取数组的Stream
package com.an.a;
import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;
//测试各种数据获取Stream
public class StreamTest1 {
/*
单列集合 default Stream<E> stream() Collection中的默认方法
双列集合 无 无法直接获取Stream流
数组 public static <T> Stream(T[]arry) Arrays类中的静态方法
一堆零散数据 public static <T>Stream<T>of(T...values)Stream接口中的静态方法
*/
public static void main(String[] args) {
//3.获取数组的Stream
int arr[]={1,2,4,5,6,8,0};
String[]str={"aaa","bbb","ddd","www"};
//获取流水线并把数组放上去
Arrays.stream(arr).forEach(s-> System.out.println(s));
//Arrays类的Stream方法有很多重载,以至于可以获取任意类型数组的流水线
final Stream<String> stream = Arrays.stream(str);//引用类型的流水线
stream.forEach(s-> System.out.println(s));
}
}
4.获取零散数据的Stream
package com.an.a;
import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;
//测试各种数据获取Stream
public class StreamTest1 {
/*
单列集合 default Stream<E> stream() Collection中的默认方法
双列集合 无 无法直接获取Stream流
数组 public static <T> Stream(T[]arry) Arrays类中的静态方法
一堆零散数据 public static <T>Stream<T>of(T...values)Stream接口中的静态方法
*/
public static void main(String[] args) {
//获取一堆零散数据的Stream
//这些零散数据可以是任意类型但是要求这些数据的类型相同
Stream.of(2, 3, 4, 5, 6).forEach(s-> System.out.println(s));
Stream.of("aaa","bbb","ccc").forEach(s-> System.out.println(s));
}
}
关于上面of方法的小细节
package com.an.a;
import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;
//测试各种数据获取Stream
public class StreamTest1 {
/*
单列集合 default Stream<E> stream() Collection中的默认方法
双列集合 无 无法直接获取Stream流
数组 public static <T> Stream(T[]arry) Arrays类中的静态方法
一堆零散数据 public static <T>Stream<T>of(T...values)Stream接口中的静态方法
*/
public static void main(String[] args) {
//3.获取数组的Stream
int arr[]={1,2,4,5,6,8,0};
String[]str={"aaa","bbb","ddd","www"};
//获取流水线并把数组放上去
Arrays.stream(arr).forEach(s-> System.out.println(s));
System.out.println("==========================================");
//Arrays类的Stream方法有很多重载,以至于可以获取任意类型数组的流水线
final Stream<String> stream = Arrays.stream(str);//引用类型的流水线
stream.forEach(s-> System.out.println(s));
System.out.println("==========of方法的小细节=========================");
//Stream里面的of方法我们用来获取零散数据的Stream
//但是我们知道of的可变参数底层是一个数组,所有也可以给它传递一个数组
//那是不是说这种方法也可以获取数组的Stream
Stream.of(1,2,4,5,6,8,0).forEach(s-> System.out.println(s));
Stream.of(arr).forEach(s-> System.out.println(s));//[I@448139f0
Stream.of(str).forEach(s-> System.out.println(s));//可以操作
//结论:如果该数组是基本数据类型,java不能对其整体自动装箱,而是将数组整体当做一个元素放到Stream中
//所有基本数据类型的数组将会得到其地址
}
}
Stream是一个类,可以理解为流水线(有容器的性质,可以将元素放在里面)
Stream流的中间方法
合并流,如果2个流的数据类型不一致,那么大流的类型就是2个流的公共父类
前3个方法
package com.an.a;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
//测试Stream流的中间方法
public class TestA {
public static void main(String[] args) {
/*
Stream<T> filter(Predicate<?super T>predicate) 过滤
limit 获取前几个元素 :Stream<T>
skip 跳过前几个元素 :Stream<T>
注意点:1.中间方法返回新的Stream流,原来的Stream流只能使用一次,建议用链式编程
2.修改原来Stream流中的数据不会影响原来数组或集合中的数据
*/
ArrayList<String> list=new ArrayList<>();
Collections.addAll(list,"张无忌","周芷若","赵敏","周强","张三丰","张三","张良","王二麻子");
//1.filter 过滤 把张开头的留下 其余数据不要
//filter的参数是函数式接口,可以传递是匿名内部类
/*list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {//s表示流中的每一个数据
//如果返回值是true,表示当前数据留下
//如果返回值是false,表示当前数据舍弃不要
return s.startsWith("张");//startwith开头有张则返回true 否则返回false
}
}).forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s );
}
});*/
//改写成Lambda
//list.stream().filter( s-> s.startsWith("张")).forEach( s-> System.out.println(s ));
//对以上注意点的验证1.原来的Stream流只能使用一次:
// final Stream<String> stream1 = list.stream();
// stream1.forEach(s-> System.out.println(s));//使用stream1对数据进行操作
// stream1.count();//第二次使用stream1进行操作:IllegalStateException(将会出现异常)
//2.操作stream原来数组或集合中的数据不变
//list.forEach(s-> System.out.println(s));
//2. limit 获取前几个元素:参数为前几个元素的个数(返回含有前几个元素的流)
// list.stream().limit(3).forEach(s-> System.out.print(s+" "));//张无忌 周芷若 赵敏
//3. skip 跳过前几个元素 :Stream<T>(返回跳过了前几个元素的流)
// list.stream().skip(3).forEach(s-> System.out.print(s+" "));//张无忌 周芷若 赵敏 周强 张三丰 张三 张良 王二麻子
//课堂练习:用limit和skip获取周强 张三丰 张三
//思路1:前跳过前3个再获取前3个
// list.stream().skip(3).limit(3).forEach(s-> System.out.print(s+" "));//周强 张三丰 张三
//思路2:前获取前6个再跳过前3个
list.stream().limit(6).skip(3).forEach(s-> System.out.print(s+" "));//周强 张三丰 张三
}
}
distinct方法用于去重,再其方法的底层是通过HashSet进行去重,而HashSet是通过equals和hashCode进行去重,所以用该方法一定要重写equals和hashCode方法,如果是java定义的类,已经帮我们重写了这2个方法,如果是我们自己定义的类则一定要重写这2个方法
package com.an.a;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
//测试Stream流的中间方法
public class TestA {
public static void main(String[] args) {
/*
distnct 元素去重(依赖hasCode和equals方法):
static<T> Strean<T> concat(Stream a,Stream b) 合并a和b两个流为一个流
*/
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌","张无忌","胡歌","张无忌","周伯通","任我行");
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2,"周芷若","小舞");
//1.元素去重 distnct (依赖equals和hasCode方法)
list1.stream().distinct().forEach(s-> System.out.print(s+" "));//张无忌 胡歌 周伯通 任我行
//因为我们的数据类型是String,java在String在已经重写了equals和hasCode,如果数据的类型是我们自己定义的类,则我们需要在类中重写这2个方法
//2.concat 将2个流合并成一个流
Stream<String> stream12 = Stream.concat(list1.stream(), list2.stream());//返回一个新的流
stream12.forEach(s-> System.out.print(s+" "));//张无忌 胡歌 周伯通 任我行 张无忌 张无忌 胡歌 张无忌 周伯通 任我行 周芷若 小舞
//如果合并的2个流的数据类型不同,则新的流的数据类型为这2个流的公共父类,这样就不能调用子类特有的方法
}
}
package com.an.a;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
//测试Stream流的中间方法
public class TestA {
public static void main(String[] args) {
/*
map 转换流中的数据类型
*/
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌-13","赵敏-34","萧峰-23","张三丰-34","郝建-23");
//需求:只获取里面的年龄并进行打印
//思路:String->int
/*
map可以转换流中的数据类型
map的参数是函数式接口
第一个类型:流中原本的数据类型
第二个类型:转换之后的数据类型
apply方法:形参表示流中每一个数据
返回值:表示转换之后的数据(流中数据的转换需要我们自己在该方法中实现)
*/
//在数据处理中我们可以先获取到年龄然后进行数据转型
//所以在下面的forEach方法中s依次表示的数据就是整数了
list.stream().map(new Function<String, Integer>() {//要就第二个类型改成目标类型
@Override
public Integer apply(String s) {//s表示流中的每一个数据
// final String[] str = s.split("-");//按照-进行截取数据 并将截取后的数据放进数组
//str[0]为姓名 str[1]为年龄
//将年龄转为int
//return Integer.parseInt(str[1]);
//简化前面2个为一步
return Integer.parseInt( s.split("-")[1]);//split返回一个数组,在前面加上下标直接变成对应的字符串
}
}).forEach(s-> System.out.print(s+" "));//13 34 23 34 23
//用Lambda进行简化处理
list.stream().map(s->Integer.parseInt(s.split("-")[1])).forEach(s-> System.out.print(s+" "));
}
}
Stream流终结方法
toArray方法有重载,空参的toArray只能返回Object类型的数组,而有参的toArray可以自己设置返回的类型
package com.an.a;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Stream;
//测试Stream流的终结方法
public class TestA {
public static void main(String[] args) {
/*
void forEach(Consumer action) 遍历
long count() 统计流中数据个数
toArray() 收集流中的数据放到数组中
*/
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张三丰","张无忌","杨过","郭靖","黄蓉");
//1.forEach遍历
/*
Consumer的泛型:表示流中数据的类型
//accept方法的形参s:依次表示流中的每一个数据
//方法体:对每一个数据的处理操作
*/
/* list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.print(s+" ");//张三丰 张无忌 杨过 郭靖 黄蓉
}
});*/
//用Lambda改写
list.stream().forEach(s-> System.out.print(s+" "));//张三丰 张无忌 杨过 郭靖 黄蓉
//2.count 统计流中数据的个数
long count = list.stream().count();
System.out.println(count);//5
//3.toArray 收集流中的数据并放在数组中
//3.1返回Object类型的数组
Object[] array = list.stream().toArray();
System.out.println(Arrays.toString(array));//[张三丰, 张无忌, 杨过, 郭靖, 黄蓉]
//3.2返回自己设置类型的数组
//其参数是函数式接口
/*
IntFunction的泛型:具体类型的数组(需要得到的数组类型)
apply的形参:流中数据的个数,要和数组的长度保持一致
apply的返回值:具体类型的数组
方法体:就是创建数组
*/
/*
toArray方法参数的作用:负责创建一个指定类型的数组
toArray方法底层:会依次得到流中的每一个数据并把数据放到数组当中
toArrray的返回值是一个装着流中所有数据的数组
*/
String[]arr= list.stream().toArray(new IntFunction<String[]>() {//将泛型该处具体类型的数组
@Override
public String[] apply(int value) {//返回类型改成具体类型的数组
return new String[value];//数组长度和流中数组的个数一致
}
});
System.out.println(Arrays.toString(arr));//[张三丰, 张无忌, 杨过, 郭靖, 黄蓉]
//将其改成Lambda
String[] array1 = list.stream().toArray(value -> new String[value]);
System.out.println(Arrays.toString(array1));//[张三丰, 张无忌, 杨过, 郭靖, 黄蓉]
}
}
收集方法collect
package com.an.a;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
//测试Stream流的终结方法
public class TestA {
public static void main(String[] args) {
//collect(Collector<? super T,A,R> collector) 收集流中的数据,放到集合中(List Set Map)
//1.收集到List集合中:要求:把所有的男性都收集起来
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌-男-12","杨过-男-24","小龙女-女-21","张三丰-男-123","黄月英-女-24");
//当前的collect方法的参数不是函数式接口而是一个普通的接口
//可以理解为collect方法可以返回各种类型的集合
List<String> list1 = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toList());
System.out.println(list1);//[张无忌-男-12, 杨过-男-24, 张三丰-男-123]
//2.收集到Set集合中:要求:把男性都收集起来
Set<String> set = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toSet());
System.out.println(set);//[杨过-男-24, 张三丰-男-123, 张无忌-男-12]
//set和List总结:收集到Set集合中可以进行去重
//3.收集到Map集合中
/*
把所有的男姓都收集起来
键:姓名 值 :年龄
*/
/*toMap:参数一表示键的生成规则
参数二表示值的生成规则
*toMap的2个参数都是函数式接口'
*参数一:
* Function泛型一:表示流里面每一个数据
* 泛型二:表示Map集合中键的数据类型
* 方法apply形参:表示流中每一个 数据
方法体:生成键的代码
返回值:已经生成的键
*
*参数一:
Function泛型一:表示流中每一个数据
泛型二:表示Map集合中值的数据类型
方法apply形参:依次表示流中每一个数据
方法体:生成值的代码
返回值:已经生成的值
*
*
*
*/
//张无忌-男-12
/* Map<String, Integer> map = 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(map);//{杨过=24, 张三丰=123, 张无忌=12}*/
//细节:收集到Map集合中键不能重复(和Map集合的性质有关)
//将其用Lambda进行简化
Map<String, Integer> map = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toMap( s-> s
.split("-")[0], s-> Integer.parseInt(s.split("-")[2])));
System.out.println(map);
}
}
Stream的综合练习
综合练习1--数字过滤
package com.an.a;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
//关于Stream的综合练习
public class StreamTestB {
public static void main(String[] args) {
/*
定义一个集合,并添加一些整数 1,2,3,4,5,6,7,8,9,10
过滤奇数,之留下偶数
并将集合保存起来
*/
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list,1,2,3,4,5,6,7,8,9,10);
//抽象方法的形参为数据 该数据保留返回true 该数据去除返回false
List<Integer> list1 = list.stream().filter(s -> s % 2 == 0).collect(Collectors.toList());//[2, 4, 6, 8, 10]
System.out.println(list1);
}
}
package com.an.a;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
//关于Stream的综合练习
public class StreamTestB {
public static void main(String[] args) {
/*
创建一个ArrayList集合,并添加以下字符串,字符串前面是姓名,后面是年龄
张三,23 lisi,24 wangwu,25
保留年龄大于等于24岁的人,并收集到Map集合中 姓名为键 年龄为值
*/
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list," 张三,23","lisi,24","wangwu,25");
/* Map<String, Integer> map = list.stream()
.filter(s -> Integer.parseInt(s
.split(",")[1]) >= 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]);
}
}));*/
//Lambda进行简写
Map<String, Integer> map = list.stream().filter(s -> Integer
.parseInt(s.split(",")[1]) >= 24)
.collect(Collectors.toMap(s -> s.split(",")[0],
s -> Integer.parseInt(s.split(",")[1])));
System.out.println(map);//{lisi=24, wangwu=25}
}
}
idea快捷键 ctrl+Alt+L格式化代码
- Actor类
package com.an.a;
public class Actor {
private String name;
private int age;
public Actor() {
}
public Actor(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Actor{name = " + name + ", age = " + age + "}";
}
}
- 程序主体
package com.an.a;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
//关于Stream的综合练习
public class StreamTestB {
public static void main(String[] args) {
/*
现在有2个ArrayList集合,分别储存6个男演员的姓名年龄和6名女演员的姓名年龄
姓名和年龄用逗号隔开
要求完成如下操作:
比如 张三,23(依次进行以下步骤)
1.男演员只要为3个字的前2个人
2.女演员只要姓杨的,并且不要第一个
3.把过滤后的男演员和女演员的姓名合并在一起
4.将上一步的演员姓名封装成Actor对象
5,将所有的演员对象都保存在List集合中
男演员:蔡坤坤,24 叶天天,23 刘不甜,22 吴签,24 谷嘉,30 萧凉凉,27
女演员:赵小颖,35 杨颖,36 高圆圆,43 张天天,31 刘诗,35 杨小幂,33
Actor类属性只有 姓名 年龄
*/
//创建2个ArrayList集合分别分别储存男女演员信息
ArrayList<String> manList = new ArrayList<>();
Collections.addAll(manList,"蔡坤坤,24","叶天天,23","刘不甜,22","吴签,24","谷嘉,30","萧凉凉,27");
ArrayList<String> womenList = new ArrayList<>();
Collections.addAll(womenList,"赵小颖,35","杨颖,36","高圆圆,43","张天天,31","刘诗,35","杨小幂,33");
// 1.男演员只要为3个字的前2个人.
Stream<String> stream1 = manList.stream().filter(s -> s.split(",")[0].length() == 3).limit(2);
// 2.女演员只要姓杨的,并且不要第一个
Stream<String> stream2 = womenList.stream().filter(s -> s.split(",")[0].startsWith("杨")).skip(1);
// 3.把过滤后的男演员和女演员的姓名合并在一起
//4.将上一步的演员姓名封装成Actor对象 (将流中的数据进行数据转换)
//Stream-->Actor
//Function 第一个参数 原数据类型
// 第二个参数 目标类型
/*
apply s表示每一个数据
返回 目标数据
*/
/*Stream.concat(stream1,stream2).map(new Function<String, Actor>() {
@Override
public Actor apply(String s) {//蔡坤坤,24
String name = s.split(",")[0];//姓名
int age = Integer.parseInt(s.split(",")[1]);//年龄
return new Actor(name,age);
}
});*/
//修改为Lambda
Stream.concat(stream1,stream2)
.map(s->new Actor(s.
split(",")[0],(Integer.parseInt(s.split(",")[1]))));
//经验教训:Stream流只能被使用一次
}
}