Java笔记_15
- 一、创建不可变集合
- 1.1、创建不可变集合的应用场景
- 1.2、创建不可变集合的书写格式
- 二、Stream流
- 2.1、体验Stream流
- 2.2、Stream流的思想和获取Stream流
- 2.3、Stream流的中间方法
- 2.4、Stream流的终结方法
- 2.5、收集方法collect
一、创建不可变集合
不可变集合:不可以被修改的集合
1.1、创建不可变集合的应用场景
- 如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践。
- 当集合对象被不可信的库调用时,不可变形式是安全的。
简单理解:不想让别人修改集合中的内容
1.2、创建不可变集合的书写格式
在List、Set、Map接口中,都存在静态的of方法,可以获取一个不可变的集合。
方法名称 | 说明 |
---|---|
static <E> List<E> of(E…elements) | 创建一个具有指定元素的List集合对象 |
static <E> Set<E> of(E…elements) | 创建一个具有指定元素的Set集合对象 |
static <K , V> Map<K, V> of(E…elements) | 创建一个具有指定元素的Map集合对象 |
注意:这个集合不能添加,不能删除,不能修改。
Set:
- 当我们要获取一个不可变的Set集合时,里面的参数一定要保证唯一性
Map:
- 键是不能重复的
- Map里面的of方法,参数是有上限的,最多只能传递20个参数,10个键值对
- 如果我们要传递多个键值对对象,数量大于10个,在Map接口中还有一个方法
package ImmutableDome;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
public class Dome1 {
public static void main(String[] args) {
List<String> list = List.of("小王","小里","小五","小陈","小黄","小路","小与");
System.out.print(list.get(0)+" ");
System.out.print(list.get(1)+" ");
System.out.print(list.get(2)+" ");
System.out.print(list.get(3)+" ");
System.out.print(list.get(4)+" ");
System.out.print(list.get(5)+" ");
System.out.print(list.get(6)+" ");
System.out.println();
System.out.println("_-----------------------------------------_");
for (String s : list) {
System.out.print (s+" ");
}
System.out.println();
System.out.println("_-----------------------------------------_");
Iterator<String> it = list.iterator();
while (it.hasNext()){
String next = it.next();
System.out.print (next+" ");
}
System.out.println();
System.out.println("_-----------------------------------------_");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.print (s+" ");
}
});
System.out.println();
System.out.println("_-----------------------------------------_");
Map<String, String> map = Map.of("小王", "南京", "小李", "广州", "小杨", "扬州", "小赵", "北京", "小张", "苏州",
"小飞", "上海", "小卢", "周口", "小黄", "资阳", "小贾", "太原");
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.print(entry+" ");
}
}
}
- 使Map集合生成不可变的集合通过
Map.copyOf()
方法操作(JDK10之后可以用) - 如果JDK版本低于10需要通过一下代码实现
HashMap<String,String> hm = new HashMap<>();
hm.put("小王", "南京");
hm.put("小李", "广州");
hm.put("小杨", "扬州");
hm.put("小飞", "上海");
hm.put("小卢", "周口");
Set<Map.Entry<String, String>> entries1 = hm.entrySet();
//把entries1变成一个数组
Map.Entry[] arr1 = new Map.Entry[0];
//toArray方法在底层会比较集合的长度跟数组的长度两者的大小
//如果集合的长度〉数组的长度﹔数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
// 如果集合的长度〈=数组的长度:数据在数组中放的下,此时不会创建新的数组,而是直接用
Map.Entry[] arr2 = entries1.toArray(arr1);
//不可变的map集合
Map map1 = Map.ofEntries(arr2);//此时就是一个不可变的集合
//链式方法
Map map2 = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));
二、Stream流
2.1、体验Stream流
package StreamDome;
import java.util.ArrayList;
public class Dome1 {
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.stream().filter(name -> name.startsWith("张")).filter(name ->name.length() == 3).forEach(name-> System.out.println(name));
ArrayList<String> list1 = new ArrayList<>();
for (String name : list) {
if(name.startsWith("张")){
list1.add(name);
}
}
System.out.println(list1);
ArrayList<String> list2 = new ArrayList<>();
for (String name : list1) {
if (name.length()==3){
list2.add(name);
}
}
System.out.println(list2);
}
}
2.2、Stream流的思想和获取Stream流
Stream流的作用:
结合了Lambda表达式,简化集合、数组的操作
Stream流的使用步骤:
- 先得到一条
Stream流
(流水线),并把数据放上去 - 利用
Stream流
中的API进行各种操作- 过滤、转换(中间方法)->方法结束之后还能调用其他方法
- 统计、打印(终结方法)->最后一步,方法调用完之后不能再调用其他方法
- 先得到一条
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接口中的静态方法 |
在对一对零散数据进行stream流时需要注意:
- stream接口中静态方法of的细节
- 方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
- 但是数组必须是引用数据类型的,如果传递基本数据类型,是会把整个数组当做一个元素,放到Stream当中。
package StreamDome;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Stream;
public class Dome2 {
public static void main(String[] args) {
//单列集合使用stream流
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"a","b","c","d","e","f","g","h","i","j","k");
//使用stream流直接打印集合
list.stream().forEach(s -> System.out.println(s));
//双列集合需要通过转化成单列集合再进行stream流
Map<String,Integer> hm = new HashMap<>();
hm.put("asd",123);
hm.put("qwe",222);
hm.put("zxc",333);
hm.put("fgh",444);
hm.put("rty",555);
//获取stream流
//需要转化成单列集合
//第一种
hm.keySet().stream().forEach(s -> System.out.println(s));
//第二种
hm.entrySet().stream().forEach((stringIntegerEntry)->System.out.println(stringIntegerEntry));
//数组使用stream流
int[] arr1 = {1,2,3,4,5,6};
String[] arr2 = {"a","c","s","d","f"};
Arrays.stream(arr1).forEach(s-> System.out.println(s));
Arrays.stream(arr2).forEach(s-> System.out.println(s));
//零散数据调用stream流(前提是同种数据类型)
Stream.of(1,2,3,4,5,6).forEach(s-> System.out.println(s));
Stream.of("a","c","s","d","f").forEach(s-> System.out.println(s));
}
}
2.3、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) | 转换流中的数据类型 |
注意一:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
注意二:修改Stream流中的数据,不会影响原来集合或者数组中的数据
注意三:使用concat
方法时要注意两个集合的类型,如果两者的类型不同则会转换成他们共同的父类
package StreamDome;
import java.nio.file.WatchService;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;
import java.util.stream.Stream;
public class Dome3 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list,"张三丰","王五六","王二麻","张三","王二","张良","王五六","张阿","王二麻","王麻");
Collections.addAll(list2,"123","345","666","444","888","999");
list.stream().filter(s->s.startsWith("张")).forEach(s -> System.out.println(s));
//提高代码阅读性
list.stream().filter(s -> s.startsWith("王"))
.filter(s->s.length()==3)
.forEach(s -> System.out.println(s));
System.out.println("===============================================");
//获取前三个元素
list.stream().limit(3).forEach(s -> System.out.println(s));
//跳过前三个元素
list.stream().skip(3).forEach(s -> System.out.println(s));
System.out.println("===============================================");
//元素去重
//底层使用的时equal和hashCode方法
list.stream().distinct().forEach(s -> System.out.println(s));
//合并a,b两个流
Stream.concat(list.stream(),list2.stream()).forEach(s -> System.out.println(s));
//stream类型转换
ArrayList<String> list3 = new ArrayList<>();
Collections.addAll(list3,"小王-12","小李-14","小张-15","小赵-16","小黄-17");
list3.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s){
String[] arr = s.split("-");
String ages = arr[1];
int age = Integer.parseInt(ages);
return age;
}
}).forEach(s-> System.out.println(s));
list3.stream().map(s -> Integer.parseInt(s.split("-")[1])).forEach(s-> System.out.println(s));
}
}
2.4、Stream流的终结方法
名称 | 说明 |
---|---|
void forEach (Consumer action) | 遍历 |
long count () | 统计 |
toArray () | 收集流中的数据,放到数组中 |
collect (Collector collector) | 收集流中的数据,放到集合中 |
- IntFunction的泛型:具体类型的数组
- apply的形参:流中数据的个数,要跟数组的长度保持一致
- apply的返回值,集体类型的数组
- 方法体:就是创建数组
- toArray方法的参数的作用:负责创建一个指定类型的数组
- toArray方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中
- toArray方法的返回值:是一个装着流里面所有数据的数组
package StreamDome;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.IntFunction;
public class Dome4 {
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);
}
});
System.out.println(list.stream().count());
Object[] objects = list.stream().toArray();
System.out.println(Arrays.toString(objects));
//IntFunction的泛型:具体类型的数组
//apply的形参:流中数据的个数,要跟数组的长度保持一致
//apply的返回值,集体类型的数组
//方法体:就是创建数组
//toArray方法的参数的作用:负责创建一个指定类型的数组
//toArray方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中
//toArray方法的返回值:是一个装着流里面所有数据的数组
String[] strings = list.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
for (int i = 0; i < strings.length; i++) {
System.out.println(strings[i]);
}
list.stream().toArray(value -> new String[value]);
}
}