一、流(Stream)
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
(集合讲的是数据,流讲的是计算!)注意:
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。它会等到需要结果的时候才执行
Stream 操作三步:
- 创建 Stream
一个数据源(如:集合、数组),获取一个流- 中间操作
一个中间操作链,对数据源的数据进行处理- 终止操作(终端操作)
一个终止操作,执行中间操作链,并产生结果
二、流(Stream)的创建
package com.Stream;
import com.lambda1.Employe;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* 一、Stream 的三个操作步骤
*
* 1、创建 Stream
*
* 2、中间操作
*
* 3、终止操作(终端操作)
*
*/
public class TestStreamAPI1{
//创建 Stream
@Test
public void test1(){
//1.可以通过 Collection 系列集合提供的 stream() 或 paralleStream()
List list = new ArrayList<>();
Stream stream1 = list.stream();
//2.通过 Arrays 中的静态方法 stream() 获取数组流
Employe[] emps = new Employe[10];
Stream stream2 = Arrays.stream(emps);
//3.通过 Stream 类中的静态方法 of()
Stream stream3 = Stream.of("aa", "bb", "cc");
//4.创建无限流
//迭代
Stream stream4 = Stream.iterate(0, x -> x + 2);
stream4.limit(10).forEach(System.out::println);
//生成
Stream stream5 = Stream.generate(() -> Math.random());
stream5.limit(10).forEach(System.out::println);
}
}
三、流(Stream)中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称之为“惰性求值”。
1、筛选与切片
筛选与切片:
filter —— 接收 Lambda,从流中排除某些元素;
limit —— 截断流,使其元素不超过给定数量;
skip(n) —— 跳过元素,返回一个仍掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补;
distinct —— 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素。
package com.Stream;
import com.lambda1.Employe;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
/**
* 一、Stream 的三个操作步骤
*
* 1、创建 Stream
*
* 2、中间操作
*
* 3、终止操作(终端操作)
*
*/
public class TestStreamAPI2 {
//中间操作
//内部迭代由 StreamAPI 完成
/**
* 筛选与切片
* filter —— 接收 Lambda,从流中排除某些元素;
* peek
* limit —— 截断流,使其元素不超过给定数量;
* skip(n) —— 跳过元素,返回一个仍掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补;
* distinct —— 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素。
*/
List employes = Arrays.asList(
new Employe("张三", 18,9999.99),
new Employe("李四", 38,5555.99),
new Employe("王五", 50,6666.66),
new Employe("赵六", 16,3333.33),
new Employe("田七", 10,7777.77),
new Employe("田七", 10,7777.77),
new Employe("田七", 10,7777.77)
);
//filter 过滤
@Test
public void test1(){
employes.stream()//创建流
.filter(e->e.getAge() >= 35)//中间操作
.forEach(System.out::println);//终止操作
}
//limit 限制
@Test
public void test2(){
employes.stream()
.filter(e->e.getSalary() >= 5000)
.limit(2)
.forEach(System.out::println);
}
//skip(n) 跳过
@Test
public void test3(){
employes.stream()
.filter(e -> e.getSalary() >= 5000)
.skip(2)
.forEach(System.out::println);
}
//distinct 去重,通过hashCode() 和 equals() 去重
@Test
public void test4(){
employes.stream()
.distinct()
.forEach(System.out::println);
}
//年龄大于10岁,工资每人加100
@Test
public void test5(){
employes.stream().filter(x -> x.getAge() > 10)
.peek(x -> x.setSalary(x.getSalary() + 100))
.forEach(System.out::println);
}
}
注意:distinct 去重的时候,Employee.java 中要覆写 equals() 和 hashCode() 方法:
package com.lambda1;
import java.util.Objects;
public class Employe {
private String name;
private int age;
private double salary;
public Employe() {
}
public Employe(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employe employe = (Employe) o;
return age == employe.age &&
Double.compare(employe.salary, salary) == 0 &&
Objects.equals(name, employe.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, salary);
}
@Override
public String toString() {
return "Employe{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
}
2、映射
映射:
map —— 接收 Lambda,将元素转换成其它形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素;
flatMap —— 接收一个函数作为参数,将流中的每个值都转换成另一个流,然后把所有流连接成一个流;
package com.Stream;
import com.lambda1.Employe;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* 一、Stream 的三个操作步骤
*
* 1、创建 Stream
*
* 2、中间操作
*
* 3、终止操作(终端操作)
*
*/
public class TestStreamAPI3 {
List employes = Arrays.asList(
new Employe("张三", 18,9999.99),
new Employe("李四", 38,5555.99),
new Employe("王五", 50,6666.66),
new Employe("赵六", 16,3333.33),
new Employe("田七", 10,7777.77)
);
/**
* 映射:
* map —— 接收 Lambda,将元素转换成其它形式或提取信息。接收一个函数作为参数,
* 该函数会被应用到每个元素上,并将其映射成一个新的元素;
* flatMap —— 接收一个函数作为参数,将流中的每个值都转换成另一个流,然后把所有流连接成一个流;
*/
@Test
public void test1(){
List list = Arrays.asList("aaa","bbb","ccc","ddd","eee");
list.stream()
// .map(e -> e.toUpperCase())
.map(String::toUpperCase)
.forEach(System.out::println);
System.out.println("--------------------------------");
employes.stream()
.map(Employe::getName)
.forEach(System.out::println);
System.out.println("--------------------------------");
list.stream()
.flatMap(TestStreamAPI3::filterCharacter)
.forEach(System.out::print);
}
public static Stream filterCharacter(String str){
ArrayList list = new ArrayList<>();
for (Character ch : str.toCharArray()){
list.add(ch);
}
return list.stream();
}
}
3、排序
排序:
sorted() —— 自然排序(Comparable);
sorted(Comparator com) —— 定制排序(Comparator);
package com.Stream;
import com.lambda1.Employe;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
/**
* 排序
*/
public class TestStreamAPI4 {
List employes = Arrays.asList(
new Employe("张三", 18,9999.99),
new Employe("李四", 38,5555.99),
new Employe("王五", 50,6666.66),
new Employe("赵六", 16,3333.33),
new Employe("田七", 10,7777.77),
new Employe("田七", 16,7777.77),
new Employe("田八", 10,7777.77)
);
/**
* 排序
* sorted() —— 自然排序(Comparable)
* sorted(Comparator com) —— 定制排序(Comparator)
*/
@Test
public void test1(){
List list = Arrays.asList("ccc","eee","aaa","ddd","bbb");
list.stream()
.sorted()
.forEach(System.out::println);
System.out.println("--------------------------------------------------");
employes.stream()
.sorted((e1, e2) -> {
if (e1.getAge() == e2.getAge()){
return e1.getName().compareTo(e2.getName());
}else {
return e1.getAge()-e2.getAge();
}
})
.forEach(System.out::println);
}
System.out.println("----------------正序排序----------------");
List employeList = employes.stream().sorted(Comparator.comparing(Employe::getAge)).collect(Collectors.toList());
employeList.forEach(System.out::println);
System.out.println("----------------倒序排序----------------");
employes.stream().sorted(Comparator.comparing(Employe::getAge).reversed()).forEach(System.out::println);
}
4、终止操作
4.1、查找与匹配
查找与匹配:
(1)allMatch —— 检查是否匹配所有元素;
(2)anyMatch —— 检查是否至少匹配一个元素;
(3)noneMatch —— 检查是否没有匹配所有元素;
(4)findFirst —— 返回第一个元素;
(5)findAny —— 返回当前流中的任意元素;
(6)count —— 返回流中元素的总数;
(7)max —— 返回流中最大值;
(8)min —— 返回流中最小值;
package com.Stream;
import com.Stream.Employe.Status;
import org.junit.Test;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
/**
* 终止操作
*/
public class TestStreamAPI5 {
List emps = Arrays.asList(
new Employe("张三", 18,9999.99, Status.FREE),
new Employe("李四", 38,5555.99, Status.BUSY),
new Employe("王五", 50,6666.66, Status.VOCATION),
new Employe("赵六", 16,3333.33, Status.FREE),
new Employe("田七", 10,7777.77, Status.BUSY),
new Employe("李八", 16,8888.88, Status.VOCATION)
);
/**
* 查找与匹配
* (1)allMatch —— 检查是否匹配所有元素;
* (2)anyMatch —— 检查是否至少匹配一个元素;
* (3)noneMatch —— 检查是否没有匹配所有元素;
* (4)findFirst —— 返回第一个元素;
* (5)findAny —— 返回当前流中的任意元素;
* (6)count —— 返回流中元素的总数;
* (7)max —— 返回流中最大值;
* (8)min —— 返回流中最小值;
*/
@Test
public void test1(){
//是否匹配所有元素
boolean b1 = emps.stream()
.allMatch(e -> e.getStatus().equals(Status.FREE));
System.out.println(b1);
//至少匹配一个元素
boolean b2 = emps.stream()
.anyMatch(e -> e.getStatus().equals(Status.FREE));
System.out.println(b2);
//没有匹配的元素
boolean b3 = emps.stream()
.noneMatch(e -> e.getStatus().equals(Status.FREE));
System.out.println(b3);
//先按工资排序,然后再找出第一个
Optional op1 = emps.stream()
// .sorted((o1, o2) -> Double.compare(o1.getSalary(), o2.getSalary()))
.sorted(Comparator.comparingDouble(Employe::getSalary))
.findFirst();
System.out.println(op1.get());
//返回当前流中的任意元素
Optional op2 = emps.parallelStream()
.filter(e -> e.getStatus().equals(Status.FREE))
.findAny();
System.out.println(op2.get());
}
@Test
public void test2(){
//总数
long count = emps.stream()
.count();
System.out.println(count);
//工资最高
Optional max = emps.stream()
// .max((x, y) -> Double.compare(x.getSalary(), y.getSalary()));
.max(Comparator.comparingDouble(Employe::getSalary));
System.out.println(max.get());
//年龄最小
Optional min = emps.stream()
// .min((x, y) -> Double.compare(x.getAge(), y.getAge()));
.min(Comparator.comparingDouble(Employe::getAge));
System.out.println(min.get());
//最低工资
Optional minSalary = emps.stream()
.map(Employe::getSalary)
.min(Double::compareTo);
System.out.println(minSalary.get());
}
}
4.2、归约与收集
归约:
reduce(T identity, BinaryOperator)/reduce(BinaryOperator) —— 可以将流中元素反复结合起来,得到一个值。备注:map 和 reduce 的连接通常称为 map-reduce 模式,因为 Google 用它来进行网络搜索而出名。
收集:
collect —— 将流转换为其他形式。接收一个 Collector 接口的实现,用于给 Stream 中元素做汇总的方法。
package com.Stream;
import org.junit.Test;
import com.Stream.Employe.Status;
import java.util.*;
import java.util.stream.Collectors;
/**
* 终止操作
*/
public class TestStreamAPI6 {
List emps = Arrays.asList(
new Employe("张三", 18,9999.99, Status.FREE),
new Employe("李四", 38,5555.99, Status.BUSY),
new Employe("王五", 50,6666.66, Status.VOCATION),
new Employe("赵六", 16,3333.33, Status.FREE),
new Employe("田七", 10,7777.77, Status.BUSY),
new Employe("田七", 16,8888.88, Status.VOCATION)
);
/**
* 归约
* reduce(T identity, BinaryOperator)/reduce(BinaryOperator) —— 可以将流中元素反复结合起来,
* 得到一个值。
*/
@Test
public void test1(){
List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(sum);
System.out.println("-------------------------------------------");
//计算工资总和
Optional op = emps.stream()
.map(Employe::getSalary)
.reduce(Double::sum);
System.out.println(op.get());
}
/**
* 收集:
* collect —— 将流转换为其他形式。接收一个Collector 接口的实现,
* 用于给 Stream 中元素做汇总的方法。
*/
@Test
public void test2(){
List list = emps.stream()
.map(Employe::getName)
.collect(Collectors.toList());
list.forEach(x->System.out.print(x+"\t\t"));
System.out.println("\n ----------------------------------------------");
Set set = emps.stream()
.map(Employe::getName)
.collect(Collectors.toSet());
set.forEach(x-> System.out.print(x+"\t\t"));
}
@Test
public void test3(){
//人员总数
Long count = emps.stream().count();
// .collect(Collectors.counting());
System.out.println("总数量:"+count);
//工资平均值
Double avgSalary = emps.stream()
.collect(Collectors.averagingDouble(Employe::getSalary));
System.out.println("平均工资:"+avgSalary);
//工资总和
Double sumSalary = emps.stream().mapToDouble(Employe::getSalary).sum();
// .collect(Collectors.summingDouble(Employe::getSalary));
System.out.println("工资总和:"+sumSalary);
//工资最大值
Optional maxSalary = emps.stream()
.max(Comparator.comparingDouble(Employe::getSalary));
// .max((x, y) -> Double.compare(x.getSalary(), y.getSalary()));
// .collect(Collectors.maxBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));
System.out.println("工资最大值:"+ maxSalary.get().getSalary());
//工资最小值
Optional minSalary = emps.stream()
.min(Comparator.comparingDouble(Employe::getSalary));
// .min((x, y) -> Double.compare(x.getSalary(), y.getSalary()));
// .collect(Collectors.minBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));
System.out.println("工资最小值:"+ minSalary.get().getSalary());
}
}
四、流(Stream)使用
1、streamAPI 练习《一》
package com.Stream;
import org.junit.Test;
import com.Stream.Employe.Status;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* streamAPI 练习
*
*/
public class TestStreamAPI7 {
List emps = Arrays.asList(
new Employe("张三", 18,9999.99, Status.FREE),
new Employe("李四", 38,5555.99, Status.BUSY),
new Employe("王五", 50,6666.66, Status.VOCATION),
new Employe("赵六", 16,3333.33, Status.FREE),
new Employe("田七", 10,7777.77, Status.BUSY),
new Employe("田七", 16,8888.88, Status.VOCATION)
);
/**
* 1.给定一个数列表,返回一个由每个数的平方根构成的列表;
* 给定【1,2,3,4,5】,应返回【1,4,9,16, 25】
*/
@Test
public void test1(){
List list = Arrays.asList(1, 2, 3, 4, 5);
List collect = list.stream()
.map(e -> e * e)
.collect(Collectors.toList());
System.out.println(collect);
Integer[] nums = new Integer[]{2, 3, 4, 5, 6};
List collect1 = Arrays.stream(nums)
.map(e -> e * e)
.collect(Collectors.toList());
System.out.println(collect1);
}
/**
* 2.用 map 和 reduce 方法数一数流中有多少个Employee?
*/
@Test
public void test2(){
Optional sum = emps.stream()
.map(e -> 1)
.reduce(Integer::sum);
System.out.println(sum.get());
System.out.println("-------------");
Optional sum2 = emps.stream()
.map(x -> 1)
// .reduce((x, y) -> Integer.sum(x, y));
.reduce(Integer::sum);
System.out.println(sum2.get());
}
}
2、streamAPI 练习《二》
(1)、创建 Trader.java 交易员实体类
package com.Stream;
/**
* 交易员
*/
public class Trader {
private String name;
private String city;
public Trader() {
}
public Trader(String name, String city) {
this.name = name;
this.city = city;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Trader{" +
"name='" + name + '\'' +
", city='" + city + '\'' +
'}';
}
}
(2)、创建 Trader.java 交易类实体类
package com.Stream;
/**
* 交易类
*/
public class Transaction {
private Trader trader;
private int year;
private int value;
public Transaction() {
}
public Transaction(Trader trader, int year, int value) {
this.trader = trader;
this.year = year;
this.value = value;
}
public Trader getTrader() {
return trader;
}
public void setTrader(Trader trader) {
this.trader = trader;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public String toString() {
return "Transaction{" +
"trader=" + trader +
", year=" + year +
", value=" + value +
'}';
}
}
(3)、实现相应的需求
1.找出2011年发生的所有交易,并按交易额排序(从高到底)
2.交易员都在哪些不同的城市工作过?
3.查找来自剑桥的交易员,并按姓名排序
4.返回所有交易员的姓名字符串,并按字母顺序排序
5.有没有交易员是在米兰工作的?
6.打印生活在剑桥的交易员的所有交易额
7.所有交易中,最高的交易额是多少?
8.找到交易额最小的交易
package com.Stream;
import org.junit.Before;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Description: //TODO streamAPI 练习
* @Author: LL
* @Date: 2019/9/25
*/
public class TestTransaction {
List transactions = null;
@Before
public void before(){
Trader raoul = new Trader("Raoul","Cambridge");
Trader mario = new Trader("Mario","Milan");
Trader alan = new Trader("Alan","Cambridge");
Trader brian = new Trader("Brian","Cambridge");
transactions = Arrays.asList(
new Transaction(brian,2011,300),
new Transaction(raoul,2012,1000),
new Transaction(raoul,2011,400),
new Transaction(mario,2012,710),
new Transaction(mario,2012,700),
new Transaction(alan,2012,950)
);
}
//1.找出2011年发生的所有交易,并按交易额排序(从高到底)
@Test
public void test1(){
transactions.stream()
.filter(e -> e.getYear()==2011)
.sorted((x, y) -> Integer.compare(x.getValue(), y.getValue()))
// .sorted(Comparator.comparingInt(Transaction::getValue))
.forEach(System.out::println);
}
//2.交易员都在哪些不同的城市工作过?
@Test
public void test2(){
transactions.stream()
.map(x -> x.getTrader().getCity())
.distinct()
.forEach(System.out::println);
}
//3.查找来自剑桥的交易员,并按姓名排序
@Test
public void test3(){
transactions.stream()
.filter(t->"Cambridge".equals(t.getTrader().getCity()))
.map(Transaction::getTrader)
.sorted(Comparator.comparing(Trader::getName))
.distinct()
.forEach(System.out::println);
}
//4.返回所有交易员的姓名字符串,并按字母顺序排序
@Test
public void test4(){
transactions.stream()
.map(t -> t.getTrader().getName())
.distinct()
.sorted()
.forEach(System.out::println);
System.out.println("-------------------------------------");
String s = transactions.stream()
.map(t -> t.getTrader().getName())
.distinct()
.sorted()
.collect(Collectors.joining());
System.out.println(s);
System.out.println("-------------------------------------");
String s2 = transactions.stream()
.map(t -> t.getTrader().getName())
.distinct()
.sorted()
.reduce("",String::concat);
System.out.println(s2);
}
//5.有没有交易员是在米兰工作的?
@Test
public void test5(){
boolean b = transactions.stream()
.anyMatch(x -> x.getTrader().getCity().equals("Milan"));
System.out.println(b);
}
//6.打印生活在剑桥的交易员的所有交易额
@Test
public void test6(){
Optional sum = transactions.stream()
.filter(t -> t.getTrader().getCity().equals("Cambridge"))
.map(Transaction::getValue)
.reduce(Integer::sum);
System.out.println(sum.get());
System.out.println("---------------------------------------");
Integer sum2 = transactions.stream()
.filter(t -> t.getTrader().getCity().equals("Cambridge"))
.map(Transaction::getValue)
.mapToInt(t -> t).sum();
// .collect(Collectors.summingInt(t -> t));
System.out.println(sum2);
}
//7.所有交易中,最高的交易额是多少?
@Test
public void test7(){
OptionalInt max = transactions.stream()
.map(Transaction::getValue)
.mapToInt(t -> t).max();
System.out.println(max.getAsInt());
System.out.println("-----------------------");
Optional max1 = transactions.stream()
.map(Transaction::getValue)
.max(Integer::compare);
System.out.println(max1.get());
}
//8.找到交易额最小的交易
@Test
public void test8(){
OptionalInt min = transactions.stream()
.map(Transaction::getValue)
.mapToInt(t -> t).min();
transactions.stream()
.filter(t -> t.getValue() <= min.getAsInt())
.forEach(System.out::println);
System.out.println("---------------------");
Optional min1 = transactions.stream()
.min(Comparator.comparingInt(Transaction::getValue));
// .min(Comparator.comparingInt(x -> x.getValue()));
// .min((x,y) -> Integer.compare(x.getValue(),y.getValue()));
System.out.println(min1.get());
}
}