📘博客主页:程序员葵安
💻︎素材来源:黑马程序员JAVA课堂
🫶感谢大家点赞👍🏻收藏⭐评论✍🏻
文章目录
一、不可变集合
1.1 不可变集合概念
长度不可变,内容也无法修改的集合
1.2 不可变集合应用场景
- 如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践。
- 当集合对象被不可信的库调用时,不可变形式是安全的。
- 简单理解:不想让别人修改集合中的内容
1.3 创建不可变集合的书写格式
方法名称 | 说明 |
---|---|
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集合对象 |
代码示例:
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Main {
public static void main(String[] args) {
/*
创建不可变的List集合
"张三","李四","王五","赵六"
*/
System.out.println("创建不可变的List集合");
//一旦创建,无法修改,只能查询
List<String> list = List.of("张三","李四","王五","赵六");
for (String s : list) {
System.out.println(s);
}
System.out.println("------------------");
/*
创建不可变的Set集合
"张三","李四","王五","赵六"
细节:参数要唯一
*/
System.out.println("创建不可变的Set集合");
Set<String> set = Set.of("张三","李四","王五","赵六");
for (String s : set) {
System.out.println(s);
}
System.out.println("------------------");
/*
创建不可变的Map集合
"河北省","石家庄"
"山西省","太原"
"辽宁省","沈阳"
"黑龙江省","哈尔滨"
细节:键是不能重复的;Map里的of方法参数有上限,最多传递20个参数,10个键值对;
如果超过10个键值对,使用Map.ofEntries方法(难记)或Map.copyOf方法(推荐)
*/
System.out.println("创建不可变的Map集合");
Map<String,String> map = Map.of(
"河北省","石家庄",
"山西省","太原",
"辽宁省","沈阳",
"黑龙江省","哈尔滨"
);
Set<String> keySet = map.keySet();
for (String key : keySet) {
String value = map.get(key);
System.out.println(key + "=" + value);
}
System.out.println("------------------");
}
}
二、Stream流
2.1 Stream流思想
2.2 Stream流作用
结合Lambda表达式,简化集合、数组的操作
2.3 Stream流使用步骤
- 先得到一条Stream流(流水线),并把数据放上去
- 使用中间方法对流水线上的数据进行操作
- 使用终结方法对流水线上的数据进行操作
2.4 步骤1获取Stream流
获取方式 | 方法名 | 说明 |
---|---|---|
单列集合 | default Stream<E> stream() | Collections中的默认方法 |
双列集合 | 无 | 无法直接使用stream流 |
数组 | public static<T> Stream<T> stream(T[] array) | Arrays工具类中的静态方法 |
一堆零散数据 | public static<T> Stream<T> of(T...values) | Stream接口中的静态方法 |
代码示例:
import java.util.*;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
//单列集合获取Stream流
System.out.println("单列集合获取Stream流");
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"a","b","c","d","e");
//获取流水线,并将集合中的数据放到流水线上
Stream<String> stream1 = list.stream();
//使用终结方法打印流水线上的所有数据
stream1.forEach(s -> System.out.println(s));
System.out.println("------------------");
//链式编程简化
list.stream().forEach(s -> System.out.println(s));
System.out.println("******************");
//双列集合获取Stream流
System.out.println("双列集合获取Stream流");
HashMap<String,Integer> hm = new HashMap<>();
hm.put("aaa",111);
hm.put("bbb",222);
hm.put("ccc",333);
hm.put("ddd",444);
//第一种获取stream流
hm.keySet().stream().forEach(s -> System.out.println(s));
System.out.println("------------------");
//第二种获取stream流
hm.entrySet().stream().forEach(s -> System.out.println(s));
System.out.println("******************");
//数组获取Stream流
System.out.println("数组获取Stream流");
int[] arr = {1,2,3,4,5,6,7,8,9,10};
String[] arr2 = {"a","b","c","d","e"};
//获取stream流
Arrays.stream(arr).forEach(s -> System.out.println(s));
System.out.println("------------------");
Arrays.stream(arr2).forEach(s -> System.out.println(s));
System.out.println("******************");
//一堆零散数据获取Stream流
System.out.println("一堆零散数据获取Stream流");
Stream.of(1,2,3,4,5).forEach(s -> System.out.println(s));
System.out.println("------------------");
Stream.of("a","b","c","d","e").forEach(s -> System.out.println(s));
}
}
Stream接口中静态方法of的细节:
- 方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
- 但数组必须是引用数据类型的,如果传递基本数据类型,是把整个数组当作一个元素,放到Stream当中
2.5 步骤2使用中间方法
方法名 | 说明 |
---|---|
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() | 返回由该流的不同元素(根据Object.equals(Object) )组成的流 |
Stream<R> map(Function<T, R> mapper) | 转换流中的数据类型 |
注意:
- 中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
- 修改Stream流中的数据,不会影响原来集合或者数组中的数据
代码示例:
import java.util.*;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰","张翠山","张良","王二麻子","谢广坤");
//filter 过滤 把张开头的留下,其余数组过滤不要
System.out.println("filter 过滤");
list.stream()
.filter(s -> s.startsWith("张"))
.forEach(s -> System.out.println(s));
System.out.println("----------------");
//limit 截取前几个元素
System.out.println("limit 截取");
list.stream()
.limit(3)
.forEach(s -> System.out.println(s));
System.out.println("----------------");
//skip 跳过前几个元素
System.out.println("skip 跳过");
list.stream()
.skip(3)
.forEach(s -> System.out.println(s));
System.out.println("----------------");
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌","张无忌","张无忌","张强","张三丰","张翠山","张良","王二麻子","谢广坤");
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2,"周芷若","赵敏");
//distinct 去重
System.out.println("distinct 去重");
list1.stream()
.distinct()
.forEach(s -> System.out.println(s));
System.out.println("----------------");
//concat 合并两个流
System.out.println("concat 合并两个流");
Stream.concat(list1.stream(),list2.stream())
.forEach(s -> System.out.println(s));
System.out.println("----------------");
//map 转换流中的数据
System.out.println("map 转换流中的数据");
ArrayList<String> list3 = new ArrayList<>();
Collections.addAll(list3,"张无忌-15","周芷若-14","赵敏-13","张强-20","张三丰-100","张翠山-40","张良-35","王二麻子-37","谢广坤-18");
list3.stream()
.map(s -> Integer.parseInt(s.split("-")[1]))
.forEach(s -> System.out.println(s));
}
}
2.6 步骤3使用终结方法
方法名 | 说明 |
---|---|
void forEach(Consumer action) | 对此流的每个元素执行操作 |
long count() | 返回此流中的元素数 |
toArray() | 收集流中的数据,放到数组中 |
collect(Collector collector) | 收集流中的数据,放到集合中 |
代码示例:
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰","张翠山","张良","王二麻子","谢广坤");
//forEach遍历
System.out.println("forEach遍历");
list.stream()
.forEach(s -> System.out.println(s));
System.out.println("----------------");
//count统计
long count = list.stream().count();
System.out.println("count统计:"+count);
System.out.println("----------------");
//toArray()
System.out.println("toArray()");
String[] arr1 = list.stream().toArray(value -> new String[value]);
System.out.println(Arrays.toString(arr1));
System.out.println("----------------");
//collect(Collector collector)
System.out.println("collect(Collector collector)");
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1, "张无忌-男-15","周芷若-女-14","赵敏-女-13","张强-男-20","张三丰-男-100","张翠山-男-40","张良-男35","王二麻子-男-37","谢广坤-男-41");
//收集到List集合
//把所有男性收集起来
System.out.println("收集到List集合");
List<String> newList = list1.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toList());
System.out.println(newList);
System.out.println("----------------");
//收集到Set集合
System.out.println("收集到Set集合");
Set<String> newSet = list1.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toSet());
System.out.println(newSet);
System.out.println("----------------");
//收集到Map集合
//键:姓名。值:年龄。
//键不能重复
System.out.println("收集到Map集合");
Map<String,String> newMap = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toMap(
s -> s.split("-")[0],
s -> s.split("-")[2]));
System.out.println(newMap);
}
}
三、方法引用
3.1 方法引用概述
把已经有的方法拿过来用,当作函数式接口中抽象方法的方法体
3.2 方法引用要求
引用处必须是函数式接口
- 被引用的方法必须已经存在
- 被引用方法的形参和返回值需要跟抽象方法保持一致
- 被引用方法的功能要满足当前需求
代码示例:
import java.util.*;
public class Main {
public static void main(String[] args) {
//需求:创建数组,进行倒序排序
Integer[] arr = {3,5,4,1,6,2};
//匿名内部类
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
System.out.println(Arrays.toString(arr));
//lambda表达式
Arrays.sort(arr,(Integer o1, Integer o2) -> {
return o2 - o1;
});
System.out.println(Arrays.toString(arr));
//lambda表达式简化格式
Arrays.sort(arr,(o1, o2) -> o2 - o1);
System.out.println(Arrays.toString(arr));
//方法引用
Arrays.sort(arr,Main::cmp);
}
public static int cmp(int o1, int o2){
return o2 - o1;
}
}
注意:::是方法引用符
3.3 方法引用分类
引用静态方法
格式:
类名::静态方法
Integer::parseInt
代码示例:
import java.util.ArrayList;
import java.util.Collections;
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"1","2","3","4","5");
list.stream()
.map(Integer::parseInt)
.forEach(s -> System.out.println(s));
}
}
引用成员方法
格式:
对象1::成员方法
其他类 其他类对象::方法名
本类 this::方法名
父类 super::方法名
本类和父类引用处不能是静态方法
引用其他类代码示例:
import java.util.ArrayList;
import java.util.Collections;
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");
//过滤数据(只要张开头,而且名字是3个字的)
//常规方法
list.stream()
.filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3)
.forEach(s -> System.out.println(s));
System.out.println("-----------------------------");
//其他类
list.stream()
.filter(new StringOperation()::stringJudge)
.forEach(s -> System.out.println(s));
System.out.println("-----------------------------");
//本类,其他类
//注意:静态方法没有this,super,所以只能再创建本类的对象
list.stream()
.filter(new Main()::stringJudge)
.forEach(s -> System.out.println(s));
}
public boolean stringJudge(String s){
return s.startsWith("张") && s.length() == 3;
}
}
引用构造方法
格式:
类名::new
Student::new
代码示例:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌,15","周芷若,14","赵敏,13","张强,20","张三丰,100","张翠山,40","张良,35","王二麻子,37");
//封装成Student对象并收集到List集合中
//常规方法
List<Student> newList1 = list.stream()
.map(s -> new Student(s.split(",")[0], Integer.parseInt(s.split(",")[1])))
.collect(Collectors.toList());
System.out.println(newList1);
//引用构造方法
List<Student> newList2 = list.stream()
.map(Student::new)
.collect(Collectors.toList());
System.out.println(newList2);
}
}
class Student{
private String name;
private int age;
public Student() {
}
public Student(String str) {
String[] arr = str.split(",");
this.name = arr[0];
this.age = Integer.parseInt(arr[1]);
}
public Student(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 "Student{name = " + name + ", age = " + age + "}";
}
}
其他调用方式
使用类名引用成员方法
格式:
类名::成员方法
String::substring
代码示例:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"aaa","bbb","ccc","ddd");
//变成大写后输出
//常规方法
list.stream()
.map(s -> s.toUpperCase())
.forEach(s -> System.out.println(s));
System.out.println("---------------------------");
//使用类名引用成员方法
list.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
}
}
引用数组的构造方法
格式:
数据类型[]::new
int[]::new
代码示例:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list,1,2,3,4,5);
//将数组收集到数组中
//常规方法
Integer[] arr1 = list.stream()
.toArray(value -> new Integer[value]);
System.out.println(Arrays.toString(arr1));
//引用数组的构造方法
Integer[] arr2 = list.stream()
.toArray(Integer[]::new);
System.out.println(Arrays.toString(arr2));
}
}
小练习:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Main {
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("zhangsan",23));
list.add(new Student("lisi",24));
list.add(new Student("wangwu",25));
//将姓名放到数组中
//常规方法
String[] arr1 = list.stream()
.map(s -> s.getName())
.toArray(String[]::new);
System.out.println(Arrays.toString(arr1));
//方法引用
String[] arr2 = list.stream()
.map(Student::getName)
.toArray(String[]::new);
System.out.println(Arrays.toString(arr2));
}
}