不可变集合:
不能被修改的集合;
应用场景:
某个数据不能够被修改,将其防御性拷贝至不可变集合中是个很好的实践,当集合对象被不可信的库调用时,不可变得形式是安全的.
创建不可变集合的书写格式:
在List,set,map接口中,都存在静态的of方法,可以获取一个不可变的集合.
创建不可变的list变量
public class immutableDemo1 {
public static void main(string[] args) {
//一旦创建完毕之后是不能进行修改的,在下列的代码中只能够执行查询操作
List<String>list = List.of("展示","各位","我");
//纯手工遍历
System.out.println(list.get(0));
System.out.println(list.get(1));
System.out.println(list.get(2));
//迭代器
Iterator<String> it = list.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
//for循环遍历
for(int i = 0;i<list.size();i++) {
String s = list.get(i);
System.out.println(s);
}
//删除会报错
list.remove("我");
//添加会报错
list.add("aaa");
//修改也会报错
list.set(0,"aaa");
}
}
创建不可变的set集合
public class immutableDemo2 {
public static void main(string[] args) {
//set中的值都是唯一的,重复的值出现会报错
Set<String> set =Set.of("as","2e","阿萨德");
//for循环遍历
for(String s : set) {
System.out.println(s);
}
//迭代器
Iterator<String> it = set.iterator();
while(it.hasNext()){
String s= it.next();
System.out.println(s);
}
//删除会报错
set.remove("我");
}
}
创建map的不可变集合
map(键1,值1,键2,值2,键3,值3......)
public class immutableDemo2 {
public static void main(string[] args) {
//map键不能够重复,map里边的of方法参数是有上限的,最多只能传递20个参数,10个键值对
//如果要传递多个键值对对象,数量大于10个的时候,可以把键值对看做是一个整体
Map<String,String> map = Map.of("张三","北京","李四","上海","王五","杭州");
//for循环遍历[
Set<String> keys = map.keySet();
for(String key:keys) {
String value = map.get(key);
System.out.println(key + "=" +value);
}
//Set<Map.Entry<获取到所有的键值对对象
Set<Map.Entry<String,String>> entries = map.entrySet();
for(Map.Entry<String,String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" +value);
}
}
}
创建map不可变集合,键值对数量超过10个
public class immutableDemo2 {
public static void main(string[] args) {
//1.创建一个普通的map集合
HashMap<String,String> hm = new HashMap<>();
hm.put("zs","22");
hm.put("3s","212");
hm.put("z1s","21232");
hm.put("z2s","2231");
hm.put("z13s","221");
hm.put("1zs","2251");
hm.put("z15s","2652");
hm.put("zs87","262");
hm.put("z7s","2452");
hm.put("z45s","2246");
//2.利用上面的数据来获取一个不可变的集合
//获取到所有的键值对对象
Set<Map.Entry<String,String>>entries = hm.entrySet();
//把entries变成一个数组
Map.Entry[] arr1 = new Map.Entry[0];
//toArray方法在底层会比较集合的长度跟数组长度两者的大小
//如果集合的长度>数组的长度:数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
//如果集合的长度<=数组的长度:数据在数组中放得下,此时不会创建新的数组,而是直接用
Map.Entry[] arr2 = entries.toArray(arr1);
//不可变得map集合
Map map= Map.ofEntries(arr2)
//2.获取不可变集合的简易方法
Map<Object,Object> map = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));
//2.获取不可变集合的java方法
Map<String,String> map = Map.copyOf(hm);
}
}
Steam流
Steam流的代码演示
创建一个集合存储多个字符串元素
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周某");
list.add("赵忌");
list.add("张无");
list.add("张三十");
(1)把所有以张开头的元素存储到新集合中
ArrayList<String> list2 = new ArrayList<>();
for(String name : list1) {
if(name.startsWith("张")){
list2.add(name);
}
}
(2)把张开头的,长度为3的元素再存储到新集合中
ArrayList<String> list3 = new ArrayList<>();
for(String name : list2) {
if(name.length() == 3){
list3.add(name);
}
}
(3)遍历打印结果
for(String name : list3) {
System.out.println(name);
}
运用Steam流,同时解决三个问题
list1.stream().filter(name->name.startsWith("张")).filter(name - > name.length() == 3).forEach(name->System.out.println(name));
Stream流的使用步骤:
一.先得到一条stream流(流水线),并把数据放上去
1.单列集合,可以使用collection中的默认方法,方法名:default Straem<E> stream()
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"23","232","12");
//获取到一条流水线,并把集合中的数据放到流水线上
Stream<String> stream1 = list.stream();
//使用终结方法打印一下流水线上的所有数据
stream1.forEach(new Consumer<String>(){
@Override
public void accept(String s) {
//s:依次表示流水线上的每一个数据
System.out.println(s);
}
});
获取到一条流水线简约写法:
list.stream().forEach(s -> System.out.println(s);)
2.双列集合,无法直接使用stream流
//创建双列集合
HashMap<String,Integer> hm = new HashMap<>();
//添加数据
hm.put("aaa",11);
hm.put("a2a",21);
hm.put("a4a",31);
hm.put("aw",15);
//直接方法在这里得不到stream流
//方法一:先调用键,得到一个单列集合
hm.KeySet().stream().forEach(s -> System.out.println(s));
//方法二:entrySet方法
hm.entrySet().stream().forEach(s -> System.out.println(s));
//直接用stream的of方法是错误的,因为数组不仅仅有引用类型,放入基本类型的话,输出会变为地址值
Stream接口中静态方法of:
方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组,但数组必须是引用数据类型的,如果传递基本数据类型,会把整个数组当做一个元素,放到Stream当中
3.数组可以使用Arrays工具类中的静态方法
//创建数组
int[] arr = {1,2,3,4,5,6,7,8,9,0};
//获取stream流
Arrays.stream(arr).forEach(s->System.out.println(s));
4.一堆零散的数据可以直接使用Stream接口中的静态方法,方法名为public static<T> Stream<T> of(T...values)
Stream.of(1,2,3,4,5).forEach(s -> System.out.println(s));
二.利用stream流中的api进行各种操作:
(一)在使用中间方法对流水线上的数据进行操作
注意:
中间方法,返回新的stream流,原先的stream流只能使用一次,建议使用链式编程,修改stream流中的数据,不会影响原来集合或者数组中的数据
用于过滤:
Stream<T>filter(Predicate<?super T> predicate)
用于获取前几个元素
Stream<T>limit(long maxSize)
用于跳过前几个元素
Stream<T>skip(long n)
ArrayList<String> list =new ArrayList<>();
Collections.addAll(list,"张三","张狗蛋","李武","李茂丹","张翠翠","张翠凤","王三王八");
//filter 过滤,把张开头的留下,其余数据都过滤不要
//写法一:
list.stream().filter(new Predicate<String>(){
@Override
public boolean test(String s) {
//如果返回值为true,则表示当前数据留下,反之不要
s.statsWith("张");
return false;
}
}).forEach(s ->System.out.println(s));
//写法二
list.stream().filter(s - s.startsWith("张")).forEach(s - > System.out.println(s));
//limit获取前几个元素,skip跳过前几个数据
list.stream().limit(3).forEach(s - > System.out.println(s));
list.stream().skip(3).forEach(s - > System.out.println(s));
元素去重,依赖(重写hashcode和equals方法)
Stream<T>distinct()
合并a和b两个流为一个流
static<T>Stream<T>concat(Stream a,Stream b)
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌","张无忌","张三三","张三","张狗蛋","李武","李茂丹","张翠翠","张翠凤","王三王八");
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2,"李狗蛋","李武");
//去重distinct
list.stream().distinct().forEach(s - > System.out.println(s));
//合并两个流concat
Stream.concat(list1.stream(),list2.stream()).forEach(s - > System.out.println(s));
转换流中的数据类型
Stream<R>map(Function<T,R> mapper)
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌-2","张三-13","张狗蛋-4","李武","李茂丹-44","张翠翠-28","张翠凤-44","王三王八-29");
//只获取里面的年龄并进行打印
//apply的形参s:依次表示流里面的每一个数据;返回值:表示转换之后的数据
list.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(s->System.out.println(s));
//表达式
list.stream().map(s - >Integer.parseInt(s.split("-")[1])).forEach(s->System.out.println(s));
(二)使用终结方法对流水线上的数据进行操作
遍历
void forEach(Consumer action)
统计
long count()
收集流中的数据,放到数组中
toArray()
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌-2","张三-13","张狗蛋-4","李武","李茂丹-44","张翠翠-28","张翠凤-44","王三王八-29");
//void forEach(Consumer action) 遍历
list.stream().forEach(new Consumer<String>(){
@Override
public void accept(String s) {
System.out.println(s);
}
});
//简化为表达式
list.stream().forEach(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的形参:流中数据的个数,要跟数组的长度保持一致;返回值:具体类型的数组;方法体:穿件数组
/*toArray方法的参数的作用:负责创建一个指定类型的数组
底层:会依次得到流里面的每一个数据,并把数据放到数组中
返回值:是一个装着流里面所有数据的数组
*/
String[] arr=list.stream().toArray(new IntFunction<? extends<String[]>(){
@Override
public String[] apply(int value) {
return new String[value];
}
});
System.out.println(Arrays.toString(arr));
//化简为表达式
list.stream().toArray(value-> new String[value]);
System.out.println(Arrays.toString(arr));
收集流中的数据,放到集合中
collect(Collector collector)
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌-女-2","张三-男-13","张狗蛋-男-4","李武-男-45","李茂丹-男-44","张翠翠-女-28","张翠凤-女-44","王三王八-女-29");
//void forEach(Consumer action) 遍历
//把所有的男性收集起来
//收集到list集合
List<String> newList = list.stream().filter(s - > "男".equals(s.split("-")[1])).collect(Collectors.toList());
System.out.println(newList);
//收集到set集合,set集合中会自动去除重复元素
Set<String> newList= list.stream().filter(s - > "男".equals(s.split("-")[1])).collect(Collectors.toSet());
System.out.println(newList);
//map集合,把姓名当做键,值当做年龄
/*
toMap:参数一键的生成规则.参数二值的生成规则
参数一:
Function:泛型一:表示流中每一个数据的类型,泛型二:Map集合中键的数据类型
方法apply形参:依次表示流中的每一个数据
方法体:生成键的代码
返回值:已经生成的键
参数二:
Function:泛型一:表示流中每一个数据的类型,泛型二:Map集合中键的数据类型
方法apply形参:依次表示流中的每一个数据
方法体:生成键的代码
返回值:已经生成的键
*/
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]);
}
}));
//表达式简化
Map<String,Integer> map2 = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toMap(
s ->s.split("-")[0],
s -> Integer.parseInt(s.split("-")[2])));