转载自:https://blog.csdn.net/weixin_40001125/article/details/105766744
案例代码:https://gitee.com/flymini/codes02/tree/master/java_/com-learn-java01
****
[TOC]
# 1. Stream
**1. 生成流**
对于集合来说,共有两个方法可以将集合转化为流。
`stream()`:为集合创建串行流。
`parallelStream()`:为集合创建并行流。
```java
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
List<String> filtered2 = strings.parallelStream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
```
**2. `forEach`迭代流中的每个数据**。以下代码片段使用 forEach 输出了10个随机数。
```java
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
```
**3. `map`用于映射每个元素到对应的结果**。以下代码片段使用 map 输出了元素对应的平方数。
```java
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
```
**4. `filter`方法用于通过设置的条件过滤出元素**。以下代码片段使用 filter 方法过滤出空字符串。
```java
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
int count = strings.stream().filter(string -> string.isEmpty()).count();
```
>[warning] 1. 如果集合存储的是引用对象,只要调用了`filter`,然后对过滤后的数据做更新,则原数据也会被修改的。对于基本数据类型的包装类和字符串则不存在这个问题。<br/> 2. 如果对过滤后的集合本身做add、remove等操作,则不会影响原集合的。
```java
List<Student> list01 = Arrays.asList(new Student("张三"),new Student("李四"),new Student("王五"));
List<Student> list02 = list01.stream().filter(l -> l.getName().equals("张三")).collect(Collectors.toList());
System.out.println("list01: " + list01);
System.out.println("list02: " + list02);
System.out.println("-----------------------");
//对过滤后的数据做修改
list02.get(0).setName("zhangsan");
System.out.println("list01: " + list01);
System.out.println("list02: " + list02);
/********** 输出如下,可见修改过滤后的数据,原数据也被修改了 ***************/
list01: [Student{name='张三'}, Student{name='李四'}, Student{name='王五'}]
list02: [Student{name='张三'}]
-----------------------
list01: [Student{name='zhangsan'}, Student{name='李四'}, Student{name='王五'}]
list02: [Student{name='zhangsan'}]
```
**5. `sorted`用于对流进行排序**。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序。
```java
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
```
**6. `limit` 方法用于获取指定数量的流**。 以下代码片段使用 limit 方法打印出 10 条数据。
```java
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
```
**7. `parallelStream` 是流并行处理程序的代替方法**。以下实例我们使用 parallelStream 来输出空字符串的数量。
```java
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.parallelStream().filter(string -> string.isEmpty()).count();
```
<br/>
# 2. Collectors
Collectors类实现了很多归约操作,例如将流转换成集合和聚合元素。
<br/>
**1. 交集**
```java
List<T> intersect = list1.stream()
.filter(list2::contains)
.collect(Collectors.toList());
```
**2. 差集**
```java
//(list1 - list2)
List<String> reduce1 = list1.stream().filter(item -> !list2.contains(item)).collect(Collectors.toList());
//(list2 - list1)
List<String> reduce2 = list2.stream().filter(item -> !list1.contains(item)).collect(Collectors.toList());
```
**3. 并集**
```java
//使用并行流
List<String> listAll = list1.parallelStream().collect(Collectors.toList());
List<String> listAll2 = list2.parallelStream().collect(Collectors.toList());
listAll.addAll(listAll2);
```
**4. 去重并集**
```java
List<String> listAllDistinct = listAll.stream()
.distinct()
.collect(Collectors.toList());
//从List中过滤出一个元素
User match = users.stream()
.filter((user) -> user.getId() == 1)
.findAny().get();
```
>[info]如果是自定义的数据类型,调用distinct去重,需要自己重写数据类型的equals与hashCode方法。
**5. `List<T>` 转 `List<U>`**
```java
//List<Person> getListPerson()
//List<Person> 转 List<User>
List<User> userList = getListPerson().stream()
.filter(p -> p != null)
.map(p -> new User(p.getName(), p.getAge()))
.collect(Collectors.toList());
```
**6. `List<T>` 转 `List<Map<String, Object>>`**
```java
//public List<Person> getListPerson()
//写法1
List<Map<Integer, Person>> mapList1 = getListPerson().stream()
.filter(p -> p != null)
.map(p -> {
Map<Integer, Person> map = new HashMap<>(1);
map.put(p.getId(), p);
return map;
})
.collect(Collectors.toList());
//写法2
List<Map<Integer, Person>> mapList2 = getListPerson().stream()
.filter(p -> p != null)
.collect(ArrayList::new, (list, p) -> {
Map<Integer, Person> map = new HashMap<>(1);
map.put(p.getId(), p);
list.add(map);
}, List::addAll);
```
**7. Map 转 List**
```java
//public Map<Integer, Person> getMapPerson()
//写法1
List<Person> personList = getMapPerson().entrySet().stream()
.filter(p -> p != null)
.sorted(Comparator.comparing(Map.Entry::getKey))
.map(p -> p.getValue())
.collect(Collectors.toList());
```
**8. List 转 Map**
```java
//写法1
//(k1, k2) -> k1 表示存在相同的键,则只保留k1对应的元素
Map<Integer, Person> personMap1 = personList.stream()
.filter(p -> p != null)
.collect(Collectors.toMap(p -> p.getId(), p -> p, (k1, k2) -> k1));
//写法2
//该写法如果存在重复的key,则会报错 Duplicate key
Map<Integer, Person> personMap2 = personList.stream()
.filter(p -> p != null)
.collect(Collectors.toMap(p -> p.getId(), p -> p));
//写法3
//如果存在相同的键,则保留第2个元素
Map<Integer, Person> personMap3 = personList.stream()
.filter(p -> p != null)
.collect(HashMap::new, (map, p) -> map.put(p.getId(), p), Map::putAll);
```
**`Map<T>` 转 `Map<U>`**
```java
//Map<Integer, Person> getMapPerson()
//Map<Integer, Person> 转 Map<Integer, User>
Map<Integer, User> userMap = getMapPerson().entrySet().stream()
.filter(p -> p != null)
.collect(Collectors.toMap(
item -> item.getKey(),
item -> new User(item.getValue().getName(), item.getValue().getAge())
));
```
**9. 其他转换为Set**
```java
//public Stream<Person> getStreamPerson()
//写法1
Set<Person> personSet1 = getStreamPerson().filter(p -> p != null).collect(HashSet::new, HashSet::add, HashSet::addAll);
//写法2
Set<Person> personSet2 = getStreamPerson().filter(p -> p != null).collect(Collectors.toSet());
```
**10. `Collectors.groupingBy` 分组后操作**
```java
//共有3个重载方法
public static <T, K> Collector<T, ?, Map<K, List<T>>>
groupingBy(Function<? super T, ? extends K> classifier)
public static <T, K, A, D> Collector<T, ?, Map<K, D>>
groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream)
public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M>
groupingBy(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory, Collector<? super T, A, D> downstream)
```
(1)分组统计。
```java
Map<String, Long> sexCount = personList.stream()
.filter(p -> p != null)
.collect(Collectors.groupingBy(Person::getSex, Collectors.counting()));
System.out.println(sexCount);
//{女=2, 男=3}
```
(2)分组求和。
```java
//写法1
Map<String, Integer> ageSum1 = personList.stream()
.filter(p -> p != null)
.collect(Collectors.groupingBy(Person::getSex, Collectors.summingInt(Person::getAge)));
//写法2
Map<String, Integer> ageSum2 = personList.stream()
.filter(p -> p != null)
.collect(Collectors.groupingBy(Person::getSex, Collectors.reducing(0, Person::getAge, Integer::sum)));
System.out.println(ageSum2);
//{女=51, 男=78}
```
(3)分组求最大值、最小值。
```java
//最大值
Map<String, Optional<Person>> ageMax = personList.stream()
.filter(p -> p != null)
.collect(Collectors.groupingBy(Person::getSex, Collectors.maxBy(Comparator.comparing(Person::getAge))));
//最小值
Map<String, Optional<Person>> ageMin = personList.stream()
.filter(p -> p != null)
.collect(Collectors.groupingBy(Person::getSex, Collectors.minBy(Comparator.comparing(Person::getAge))));
System.out.println(ageMax);
//{女=Optional[Person{id=1004, name='小梅', age=26, sex='女'}]
// , 男=Optional[Person{id=1005, name='王五', age=27, sex='男'}]}
System.out.println(ageMin);
//{女=Optional[Person{id=1003, name='小美', age=25, sex='女'}]
// , 男=Optional[Person{id=1001, name='张三', age=25, sex='男'}]}
```
(4)分组求均值。
```java
Map<String, Double> ageAvg = personList.stream()
.filter(p -> p != null)
.collect(Collectors.groupingBy(Person::getSex, Collectors.averagingInt(Person::getAge)));
System.out.println(ageAvg);
//{女=25.5, 男=26.0}
```
(5)根据性别分组。
```java
//写法1
Map<String, List<Person>> personListMap1 = personList.stream()
.filter(p -> p != null)
.collect(Collectors.groupingBy(Person::getSex, Collectors.mapping(p -> p, Collectors.toList())));
//写法2
Map<String, List<Person>> personListMap2 = personList.stream()
.filter(p -> p != null)
.collect(Collectors.groupingBy(Person::getSex, Collectors.toList()));
//写法3
Map<String, List<Person>> personListMap3 = personList.stream()
.filter(p -> p != null)
.collect(Collectors.groupingBy(Person::getSex));
System.out.println(personListMap3);
//{女=[Person{id=1003, name='小美', age=25, sex='女'}, Person{id=1004, name='小梅', age=26, sex='女'}],
// 男=[Person{id=1001, name='张三', age=25, sex='男'}, Person{id=1002, name='李四', age=26, sex='男'},
// Person{id=1005, name='王五', age=27, sex='男'}]}
```
**11. `Collectors.partitioningBy` 分组后操作**
Collectors.partitioningBy 与 Collectors.groupingBy 不同的是:Collectors.partitioningBy 只能分为两组,`true`为一组,`false`为一组。
```java
//共有2个重载方法
public static <T> Collector<T, ?, Map<Boolean, List<T>>>
partitioningBy(Predicate<? super T> predicate)
public static <T, D, A> Collector<T, ?, Map<Boolean, D>>
partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream)
```
(1)例。
```java
Map<Boolean, List<Person>> personListMap = personList.stream()
.filter(p -> p != null)
.collect(Collectors.partitioningBy(p -> "男".equals(p.getSex())));
System.out.println(personListMap);
//{false=[Person{id=1003, name='小美', age=25, sex='女'}, Person{id=1004, name='小梅', age=26, sex='女'}],
// true=[Person{id=1001, name='张三', age=25, sex='男'}, Person{id=1002, name='李四', age=26, sex='男'},
// Person{id=1005, name='王五', age=27, sex='男'}]}
Map<Boolean, Integer> ageSum = personList.stream()
.filter(p -> p != null)
.collect(Collectors.partitioningBy(p -> "男".equals(p.getSex()), Collectors.summingInt(Person::getAge)));
System.out.println(ageSum);
//{false=51, true=78}
```
**12. `Collectors.joining`字符串连接**
```java
//共有2个重载方法
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter)
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter, //分割符
CharSequence prefix, //前缀符号
CharSequence suffix) //后缀符号
```
(1)例。
```java
String nameString = personList.stream()
.filter(p -> !Objects.isNull(p))
.map(Person::getName)
.collect(Collectors.joining(",", "[", "]"));
System.out.println(nameString);
//[张三,李四,小美,小梅,王五]
```
**13. `Collectors.summarizing(Int/Long/Double)`**
一次性求出平均值averaging、总数couting、最小值minBy、最大值maxBy、求和suming。
```java
Map<String, IntSummaryStatistics> sisMap = personList.stream()
.filter(p -> !Objects.isNull(p))
.collect(Collectors.groupingBy(Person::getSex, Collectors.summarizingInt(Person::getAge)));
System.out.println("男:" + sisMap.get("男").getMax() + ", "
+ sisMap.get("男").getMin() + ", " + sisMap.get("男").getAverage()
+ ", " + sisMap.get("男").getCount() + ", " + sisMap.get("男").getSum());
//男:27, 25, 26.0, 3, 78
System.out.println("女:" + sisMap.get("女").getMax() + ", "
+ sisMap.get("女").getMin() + ", " + sisMap.get("女").getAverage()
+ ", " + sisMap.get("女").getCount() + ", " + sisMap.get("女").getSum());
//女:26, 25, 25.5, 2, 51
```
- 网络通信
- 网络协议
- 端口和套接字
- TCP网络程序
- UDP网络程序
- 多线程聊天室
- 多线程
- 线程相关概念
- 线程实现方式
- 中断线程
- 线程生命周期
- 线程优先级
- 优先级规则
- 案例演示
- 线程同步机制
- 线程同步机制
- synchronized关键字
- ReentrantLock类
- Condition类
- 监视器概念
- volatile关键字
- final变量
- 死锁
- 线程局部变量
- 读/写锁
- 原子类
- 阻塞队列
- 工作规则
- 案例演示
- 常用阻塞队列
- 线程安全集合
- 高效的映射/集/队列
- 并发集视图
- 写数组的拷贝
- Arrays类的并行数组算法
- 同步包装器
- Callable与Future
- 执行器
- 线程池
- 预定执行
- 控制任务组
- Fork-Join框架
- 同步器
- 同步器
- 信号量
- CountDownLatch类
- CyclicBarrier类
- Exchanger类
- SynchronousQueue类
- 线程与Swing
- Swing与线程问题
- 两个原则
- Swing工作线程
- 单一线程规则
- 文件IO
- File类
- 文件输入输出
- ZIP压缩文件
- 集合
- 集合框架
- 集合接口
- 集合实现类
- 线程安全集合
- 集合算法
- 迭代器
- 集合排序
- JDBC
- JDBC是什么
- JDBC-ODBC桥
- JDBC驱动程序类型
- JDBC常用类与接口
- 数据库操作
- 连接数据库
- 增/删/改/查/预处理
- 事务
- 批处理
- commons-dbutils工具
- 安全问题
- Jedis
- 使用Jedis操作Redis数据库
- JSON转换
- 使用连接池
- 案例
- 单例破坏
- 单例定义
- 单例实现方式
- 懒汉式实现单例
- 饿汉式实现单例
- 单例破坏
- 类的单例破坏
- 枚举的单例破坏
- 克隆
- 克隆是什么
- 浅克隆
- 深克隆
- 注解
- 注解是什么
- 三大注解
- 内置注解
- 元注解
- 自定义注解
- NIO
- 相关概念
- BIO/NIO/AIO
- 多线程编程
- 线程同步
- 线程通信
- NIO
- NIO三大核心组件
- NIO网络编程
- NIO文件读写
- AIO
- Java8新特性
- Lambda表达式
- 方法引用
- 函数式接口
- 默认方法
- 什么是默认方法
- 默认方法语法格式
- 多个同名的默认方法问题
- 静态默认方法
- 默认方法实例
- Stream
- Stream是什么
- Stream示例
- Optional容器
- 新的日期时间API
- Base64
- SPI
- SPI是什么
- SPI与API的区别
- 常见场景
- 使用SPI需遵循的约定
- SPI使用步骤