笔记 Java8 Stream API
# Stream API## **Stream API 三部曲**
- **创建流**
- **中间操作**
- **中止操作**
## 1. 创建流
```java
/*
* 1. 创建Stream的方式
*/
// collection.stream()
Stream<Employee> stream1 = employees.stream();
// Arrays.stream(T[] array)
Stream<Employee> stream2 = Arrays.stream(empArr);
// Stream.of(T[] arr)
Stream<Employee> empArr = Stream.of(this.empArr);
// Stream.iterate(seed,UnaryOperator<>)
Stream<Integer> stream4 = Stream.iterate(0, x -> x + 2);
// Stream.generate(Supplier<>)
Stream<Double> stream5 = Stream.generate(() -> Math.random());
```
## 2. 中间操作
### 2.0 一次加载,惰性求值
- 如果没有终止操作,中间操作不会有任何输出
```java
/**
* 无中止操作是么有任何输出的,因为Stream是一次加载,“惰性求值”
*/
@Test
public void test02() {
employees.stream().filter(e -> {
System.out.println("中间操作:" + e.getName() + "是" + e.getAge() + "岁");
return e.getAge() > 35;
});
}
```
### 2.1 筛选
```java
/**
* 中间操作
* 筛选
* 筛选年纪大于35岁的人员
* 内部迭代输出
*/
@Test
public void test01() {
employees.stream()
.filter(e -> {
System.out.println("中间操作:" + e.getName() + "是" + e.getAge() + "岁");
return e.getAge() > 35;
})
.forEach(System.out::println);
}
```
### 2.2 切片
#### 2.2.1 limit
**limit(Long num)—— 截断前num个元素,之后不会向后迭代**
```java
/**
* 切片操作
* 只取前两个
*/
@Test
public void test05() {
employees.stream()
.limit(2)
.forEach(System.out::println);
}
```
**limit切片会导致短路,也即是不会继续向后迭代:**
```java
/**
* 切片操作
* limit会造成短路
*/
@Test
public void test05_2() {
employees.stream()
.filter(employee -> {
System.out.println("短路");
return employee.getSalary()>3000;
})
.limit(2)
.forEach(System.out::println);
}
```
#### 2.2.2 skip
**Skip(Long num) —— 跳过前num个元素**
```java
/**
* 切片操作
* 跳过前两个
*/
@Test
public void test06() {
employees.stream()
.skip(2)
.forEach(System.out::println);
}
```
### 2.3 排序
#### 2.3.1 自然排序
`Stream<T> sorted();`
```java
/**
* 自然排序
*/
@Test
public void test03_1(){
int[] arr = {1,5,9,3,2,7,6,9};
Arrays.stream(arr).sorted().forEach(System.out::println);
}
```
#### 2.3.2 定制排序
**复杂的对象需要定制排序规则**
`Stream<T> sorted(Comparator<? super T> comparator);`
```java
/**
* 排序操作
* 按照工资正序排序
*/
@Test
public void test03() {
employees.stream()
.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
.forEach(System.out::println);
}
```
### 2.4 去重
#### 2.4.1 默认去重
`Stream<T> distinct();`
```java
/**
* 去重操作
* 通过流生成的hashCode和equals方法去重
* 若是对象没有重写hashcode和equals方法,将无法成功去重
*/
@Test
public void test04() {
employees.stream()
.distinct()
.forEach(System.out::println);
}
```
#### 2.4.4 定制去重
参考: https://blog.csdn.net/haiyoung/article/details/80934467
https://www.concretepage.com/java/jdk-8/java-8-distinct-example
**a 重写Employee的hashCode 和 equals方法**
**因为sorted()是基于 hashCode() 和 equals() 方法进行工作,所以第一个方法是重写这两个方法。**
**b 借助filter过滤**
`Stream<T> filter(Predicate<? super T> predicate);`
- 创建去重的规则,返回Predicate类型
```java
static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Map<Object, Boolean> employeeMap = new ConcurrentHashMap<>();
return e -> employeeMap.putIfAbsent(keyExtractor.apply(e), Boolean.TRUE) == null;
}
```
- 使用
```java
/**
* 对象去重
* 按照指定的方式去重
*/
@Test
public void test04_1() {
employees.stream()
.filter(distinctByKey(employee -> employee.getId()))
.forEach(System.out::println);
}
```
### 2.5 映射
#### 2.5.1 map映射
**对流中每一个元素进行操作**
```java
/**
* map
* 对每一个元素进行操作
*/
@Test
public void test01(){
employees.stream().map(employee -> employee.getName().toLowerCase()).forEach(System.out::println);
}
```
**提取对象的元素**
```java
/**
* map
* 提取元素
*/
@Test
public void test02(){
employees.stream().map(Employee::getName).distinct().forEach(System.out::println);
}
```
狸猫换太子
需要遍历map ,找到所有value(对象列表)添加新对象
```java
// dailyMap,目前已有的map -- Map<String, List<CapitalDaily>>
Map<String, List<CapitalDaily>> map = dailyMap.entrySet().stream().map(entry -> {
String key = entry.getKey();
List<CapitalDaily> value = entry.getValue();
List<CapitalDaily> dailies = value.stream().filter(li -> null != li.getDate() && li.getDate().equals(date)).filter(i -> i.getBalance() != null).collect(Collectors.toList());
BigDecimal balance = dailies.get(dailies.size() - 1).getBalance();
BigDecimal creditAmount = value.stream().filter(li -> null != li.getDate() && li.getDate().equals(date)).filter(i -> i.getCreditAmount() != null).map(CapitalDaily::getCreditAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal debitAmount = value.stream().filter(li -> null != li.getDate() && li.getDate().equals(date)).filter(i -> i.getDebitAmount() != null).map(CapitalDaily::getDebitAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
CapitalDaily daily = new CapitalDaily();
// daily.setDate(date);
daily.setBalance(balance.equals(BigDecimal.valueOf(0)) ? null : balance);
daily.setCreditAmount(creditAmount.equals(BigDecimal.valueOf(0)) ? null : creditAmount);
daily.setDebitAmount(debitAmount.equals(BigDecimal.valueOf(0)) ? null : debitAmount);
ArrayList<CapitalDaily> newDaily = new ArrayList<>(value);
newDaily.add(daily);
return new AbstractMap.SimpleEntry<>(key, newDaily);
}).collect(Collectors.toMap(Map.Entry::<String, List<CapitalDaily>>getKey, Map.Entry::<String, List<CapitalDaily>>getValue));
return map;
```
#### 2.5.2 flatMap映射
```java
/**
* flatMap
* 将字符串拆分打印
*/
@Test
public void test03(){
Stream<Stream<Character>> streamStream = list.stream()
.map(Demo03_map::departString);
streamStream.forEach(s -> s.forEach(System.out::println));
System.out.println("===============biu~~ =======================");
Stream<Character> characterStream = list.stream()
.flatMap(Demo03_map::departString);
characterStream.forEach(System.out::println);
}
/**
* 切割字符串的方法,返回一个流
* @Param str 要切割的字符串
* @Return characters.stream():Stream<Character>
*/
public static Stream<Character> departString(String str){
List<Character> characters = new ArrayList<>();
for (char c : str.toCharArray()) {
characters.add(c);
}
return characters.stream();
}
```
## 3. 终止操作
### 3.1 查找与匹配
#### 3.1.1 allMatch 是否匹配所有元素
```java
/**
* matchAll,是否匹配所有元素
*/
@Test
public void test01(){
boolean b = employees.stream()
.allMatch(employee -> employee.getAge() > 25);
System.out.println(b); // false
}
```
#### 3.1.2 anyMatch 是否匹配至少一个元素
```java
/**
* anyMatch 是否匹配到至少一个元素
*/
@Test
public void test02(){
boolean b = employees.stream()
.anyMatch(employee -> employee.getAge() > 25);
System.out.println(b); // true
}
```
#### 3.1.3 noneMatch 是否没有匹配所有元素
```java
/**
* noneMatch 是否没有匹配所有元素
*/
@Test
public void test03(){
boolean b = employees.stream()
.noneMatch(employee -> employee.getAge() > 25);
System.out.println(b); // false
}
@Test
public void test03_1(){
boolean b = employees.stream()
.noneMatch(employee -> employee.getAge() > 125);
System.out.println(b); // true
}
```
#### 3.1.4 findFirst 返回第一元素
```java
/**
* findFirst 返回第一元素
*/
@Test
public void test04(){
Optional<Employee> first = employees.stream()
.filter(employee -> employee.getAge() > 25)
.findFirst();
System.out.println(first); // false
}
```
#### 3.1.5 findAny 返回任意元素
```java
/**
*findAny 返回任意元素
*/
@Test
public void test05(){
Optional<Employee> first = employees.stream()
.filter(employee -> employee.getAge() < 25)
.findAny();
System.out.println(first);
}
```
#### 3.1.6 count 返回流中元素总个数
```java
/**
* count 返回流中元素总个数
*/
@Test
public void test06(){
long count = employees.stream().count();
System.out.println(count); // 7
}
```
#### 3.1.7 max 返回流中最大值
```java
/**
* max 返回流中最大值
*/
@Test
public void test07(){
Optional<Employee> max = employees.stream()
.max((e1, e2) -> e1.getAge() - e2.getAge());
System.out.println(max==null?"null":max.get().getAge()); // 93
}
```
#### 3.1.8 min 返回流中最小值
```java
/**
* min 返回流中最小值
*/
@Test
public void test08(){
Employee employee = employees.stream()
.min((e1, e2) -> e1.getAge() - e2.getAge()).orElse(null);
System.out.println(employee==null?"null":employee.getAge()); // 23
// Employee【id=2, name='SI LI', salary=4500.0, age=23】
System.out.println(employee);
}
```
### 3.2 归约和收集
#### 3.2.1 reduce
**reduce-- -- -- 将流中元素反复结合,得到一个新的值**
```java
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
/**
* 归约,求和
*/
@Test
public void test01(){
Integer sum = list.stream()
.reduce(1, (t, s) -> t + s);// 初始为1
System.out.println(sum); // 46
}
```
```java
/**
* 获取员工工资总和
* map-reduce 模式
*/
@Test
public void test02(){
Double salarySum = employees.stream()
.map(Employee::getSalary)
// .reduce((double) 0, (s1, s2) -> s1 + s2);
.reduce(Double::sum).orElse(0.0D);
System.out.println(salarySum); // 44500.0
}
```
#### 3.2.2 collectors
##### 1 toList()/toSet()
```java
/**
* 收集名字到list/set里
*/
@Test
public void test01() {
List<String> list = employees.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("===========================");
Set<String> set = employees.stream()
.map(Employee::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);
}
```
##### 2 HashSet/LinkedHashSet
```java
/**
* 收集名字到HashSet/LinkedHashSet里
*/
@Test
public void test02() {
Set<String> set = employees.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(LinkedHashSet::new));
set.forEach(System.out::println);
}
ArrayList<IdtCorpBasic> disList = list.stream().collect(
Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(IdtCorpBasic::getUscc))), ArrayList::new)
);
```
##### 3 计数 count
```java
/**
* 总数
*/
@Test
public void test03() {
Long count = employees.stream()
.map(Employee::getName)
.collect(Collectors.counting());
// .count();
System.out.println(count); // 7
}
```
##### 4 平均值 averagingDouble
```java
/**
* 平均值
*/
@Test
public void test04() {
double count = employees.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(count); // 6357.142857142857
System.out.println(String.format("0.00", count)); //0.00
}
```
##### 5 最大值 maxBy
```java
/**
* 最大值
*/
@Test
public void test05() {
Employee employee = employees.stream()
.collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))).orElse(null);
System.out.println(employee.getSalary()); // 9000.0
```
##### 6 最小值 minBy
```java
/**
* 最小值
*/
@Test
public void test06() {
Double minSalary = employees.stream()
.map(Employee::getSalary)
.collect(Collectors.minBy(Double::compare)).orElse(null);
System.out.println(minSalary); // 3500.0
}
```
##### 7 分组 groupingBy
```java
/**
* 分组
*/
@Test
public void test07_1() {
Map<Integer, List<Employee>> byAge = employees.stream()
.collect(Collectors.groupingBy(Employee::getAge));
for (Map.Entry<Integer, List<Employee>> age : byAge.entrySet()) {
System.out.println(age.getKey() + ":" + age.getValue());
}
}
/**
* 多属性拼接为key
*/
@Test
public void test07_2() {
Map<String, List<Employee>> byIdAndName = employees.stream()
.collect(Collectors.groupingBy(e -> ((Employee) e).getId() + "--" + ((Employee) e).getName()));
for (Map.Entry<String, List<Employee>> map : byIdAndName.entrySet()) {
System.out.println(map.getKey() + ":" + map.getValue());
}
}
```
```java
/**
* 多级分组
*/
@Test
public void test08() {
Map<String, Map<Object, List<Employee>>> levMap = employees.stream()
.collect(Collectors.groupingBy(Employee::getName, Collectors.groupingBy(e -> {
if (((Employee) e).getAge() <= 35) {
return "青年";
} else if (((Employee) e).getAge() <= 55) {
return "中年";
} else {
return "老年";
}
})));
System.out.println(levMap.getClass());// class java.util.HashMap
for (Map.Entry<String, Map<Object, List<Employee>>> lev : levMap.entrySet()) {
System.out.println(lev.getKey() + ":" + lev.getValue());
}
}
```
##### 8 分区 partitioningBy
```java
/**
* 分区
*返回一个map,内部有key为true和false的两个对象列表
*/
@Test
public void test09(){
Map<Boolean, List<Employee>> depart = employees.stream()
.collect(Collectors.partitioningBy(e -> e.getAge() > 30)
);
for (Map.Entry<Boolean, List<Employee>> part : depart.entrySet()) {
System.out.println(part.getKey() + ":" + part.getValue());
}
/*
false:
true:
*/
}
```
##### 9 拼接 joining
```java
/**
* 拼接
*/
@Test
public void test11(){
String names = employees.stream()
.map(Employee::getName)
// prefix和suffix是拼接之后,整体的前后缀
.collect(Collectors.joining(",", "=", "="));
System.out.println(names);
}
``` 瞅瞅图片 感谢分享,非常实用
页:
[1]