1. Stream 关注的是对数据的运算,与CPU打交道
集合关注的是数据存储,与内存打交道
2.特点
(1) 自己不会存储元素
(2) 不会改变源对象。相反,他们会返回一个持有结果的新的Stream
(3) 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
3. Stream执行流程
(1) Stream实例化
(2) 一系列的中间操作(过滤、映射...)
(3) 终止操作
4. 说明
(1) 一个中间操作链,对数据源的数据进行处理
(2) 一旦执行终止操作,就执行中间操作链,共产生结果。之后,不会再被使用
数据准备
Employee类
public class Employee {
private int id;
private String name;
private int age;
private double salary;
public Employee(int id, String name, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public Employee() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 String toString() {
return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
long temp;
temp = Double.doubleToLongBits(salary);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (age != other.age)
return false;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))
return false;
return true;
}
}
EmployeeData
import java.util.ArrayList;
import java.util.List;
public class EmployeeData {
public static List<Employee> getEmployee(){
List<Employee> list=new ArrayList<>();
list.add(new Employee(1001,"马化腾",34,6000.38));
list.add(new Employee(1002,"马云",12,9876.12));
list.add(new Employee(1003,"刘强东",34,3000.82));
list.add(new Employee(1004,"雷军",26,7657.37));
list.add(new Employee(1005,"李彦宏",65,5555.32));
list.add(new Employee(1006,"比尔盖茨",42,9500.43));
list.add(new Employee(1007,"任正非",26,4333.32));
list.add(new Employee(1008,"扎克伯格",35,2500.32));
return list;
}
}
Stream的实例化方法
public class StreamAPITest {
/**
* 测试Stream的实例化
*/
// 创建Stream 方式一: 通过集合
public void test1() {
List<Employee> employees= EmployeeData.getEmployee();
// default Stream<E> stream() : 返回一个顺序流
Stream<Employee> stream = employees.stream();
// default Stream<E> parallelStream(): 返回一个并行流
Stream<Employee> parallelStream = employees.parallelStream();
}
//创建 Stream 方式二: 通过数组
@Test
public void test2() {
int [] arr = {1,2,3,4,5,6};
//调用Arrays类的static<T> Stream<T> stream (T [] array) :返回一个流
IntStream stream = Arrays.stream(arr);
Employee e1 = new Employee(100,"Tom", 0, 0);
Employee e2 = new Employee(100,"Tom", 0, 0);
Employee [] arr2 = {e1,e2};
Stream<Employee> stream2= Arrays.stream(arr2);
}
//创建Stream方式三:通过Stream的of()
@Test
public void test3() {
Stream<Integer> stream=Stream.of(1,2,3,4,5,6);
}
//创建Stream方式四: 创建无限流
@Test
public void test4() {
//遍历前10个偶数
Stream.iterate(0, t->t+2).limit(10).forEach(System.out::println);
System.out.println("------------------");
//打印10个随机小数
Stream.generate(Math::random).limit(10).forEach(i->System.out.println(i));
}
}
Stream的中间操作
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
public class StreamAPITest2 {
/**
* 测试Stream的中间操作
*/
// 1. 筛选和切片
@Test
public void test1() {
List<Employee> list=EmployeeData.getEmployee();
System.out.println("---------filter------");
// filter(Predicate p) ----接收 Lambda,从流中排除某些元素
Stream<Employee> stream=list.stream();
// 练习:查询员工表中,员工工资大于7000的员工信息
stream.filter(e -> e.getSalary()>7000).forEach(i->System.out.println(i));
System.out.println("------limit(n)--------");
//limit(n) 截断流 ,使其元素不超过给定数量
list.stream().limit(3).forEach(System.out::println);
System.out.println("----skip(n)------");
// skip(n) --跳过元素,返回一个扔掉了前n个元素的流
list.stream().skip(3).forEach(i->System.out.println(i));
//distinct() --筛选,通过流所生成元素的hasnCode()和equals() 去除重复元素
System.out.println("-------------------distinct-------------");
list.add(new Employee(1010,"刘强东",40,8000));
list.add(new Employee(1010,"刘强东",40,8000));
list.add(new Employee(1010,"刘强东",40,8000));
list.add(new Employee(1010,"刘强东",40,8000));
list.add(new Employee(1010,"刘强东",40,8000));
list.add(new Employee(1010,"刘强东",40,8000));
list.stream().distinct().forEach(i->System.out.println(i));
}
//映射
@Test
public void test2() {
//map (function f) --接收一个函数作为参数,将元素转换为其他形式或提取信息
List<String> list = Arrays.asList("aa","bb","cc","dd");
list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
//练习:获取员工姓名长度大于3的员工姓名
System.out.println("---------nameStreamFilter----------");
List<Employee> employees = EmployeeData.getEmployee();
Stream<String> nameStream = employees.stream().map(e -> e.getName());
nameStream.filter(name -> name.length()>3).forEach(System.out::println);;
System.out.println("------------");
//flatMap(Function f) -- 接收一个函数作为参数,将流中的每个值换位另一个流,然后把所有的流连成一个流
Stream<Character> charStream = list.stream().flatMap(StreamAPITest2::fromStringToStream);
charStream.forEach(System.out::println);
}
//将字符串中的多个字符串构成的集合转换为对应的Stream实例
public static Stream<Character> fromStringToStream(String str){
ArrayList<Character> list= new ArrayList<>();
for(Character c:str.toCharArray()) {
list.add(c);
}
return list.stream();
}
//3--排序
@Test
public void test4() {
//sorted--自然排序
System.out.println("----sorted--------");
List<Integer> list = Arrays.asList(12,43,65,34,87,0,-98,7);
list.stream().sorted().forEach(System.out::println);
//sorted(Compare com) -- 定制排序
System.out.println("------sorted(com)-----");
List<Employee> employees = EmployeeData.getEmployee();
employees.stream().sorted( (e1,e2)->{
return (e1.getAge()-e2.getAge());
} ).forEach(System.out::println);
}
}
测试终止植操作
1. 匹配和查找
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
/**
* 测试终止操作
* @author CharlieLiang
*
*/
public class StreamAPITest3 {
//1-- 匹配与查找
@Test
public void test1() {
List<Employee> employees = EmployeeData.getEmployee();
//allMath(Predicate p) -- 检查是否匹配所有元素
// 练习:是否所有员工的年龄都大于18
System.out.println("-------allMath----------");
boolean allMath= employees.stream().allMatch( e -> e.getAge()>10);
System.out.println(allMath);
System.out.println("--------anyMatch----------");
//anyMatch(Predicate p) -- 检查是否至少匹配一个袁术
//练习:是否存在员工工资大于10000
boolean anyMatch = employees.stream().anyMatch( e -> e.getSalary()>1000);
System.out.println(anyMatch);
System.out.println("----noneMath-------");
//练习: 是否不存在员工姓雷
boolean noneMath = employees.stream().noneMatch( e -> e.getName().startsWith("雷"));
System.out.println(noneMath);
System.out.println("------findFirst------");
Optional<Employee> firstEmployee = employees.stream().findFirst();
System.out.println(firstEmployee);
System.out.println("--------findAny-----------");
Optional<Employee> findAny = employees.parallelStream().findAny();
System.out.println(findAny);
}
@Test
public void test2() {
List<Employee> employees = EmployeeData.getEmployee();
// count -- 返回流中元素的总个数
System.out.println("---------count-----------");
long count = employees.stream().filter( e -> e.getSalary()>5000).count();
System.out.println(count);
// 练习返回最高工资
System.out.println("--------max--------");
Stream<Double> salaryStream = employees.stream().map( e -> e.getSalary());
Optional<Double> maxSalary = salaryStream.max(
(s1,s2) -> {
return (int) (s1-s2);
}
);
System.out.println(maxSalary);
System.out.println("--------max2------");
Stream<Double> salaryStream2 = employees.stream().map( e -> e.getSalary());
Optional<Double> maxSalary2 = salaryStream2.max(Double::compare);
System.out.println(maxSalary2);
// 返回最低工资的员工
System.out.println("---min---");
Optional<Employee> minSalaryEmployee =
employees.stream().min( (e1,e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(minSalaryEmployee);
//forEach (Consumer c) --- 内部迭代
employees.stream().forEach(i -> System.out.println(i));
// 或者
// employees.forEach(System.out::println);
}
}
2. 归约测试
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
/**
* 归约测试
* @author CharlieLiang
*
*/
public class StreamAPITest4 {
@Test
public void test1() {
//reduce (T identity, BinaryOperator) -- 可以将流中的元素反复结合起来,得到一个值。返回T
// 练习计算1-10的自然数的和
System.out.println("----reduce-----");
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
// 0: 表示初始值是0
Integer sum = list.stream().reduce(0 , Integer::sum);
System.out.println(sum);
System.out.println("---reduce2----");
List<Integer> list2 = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
// 0: 表示初始值是0
Integer sum2 = list2.stream().reduce(0 , (a,b) -> (a+b));
System.out.println(sum2);
System.out.println("-----reduce(Optional T)---");
// reduce(BinaryOperator b)--可以将流中元素反复结合起来,得到一个值。返回 Optional<T>
List<Employee> employees = EmployeeData.getEmployee();
Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
Optional<Double> salarySum = salaryStream.reduce(Double::sum);
System.out.println(salarySum);
System.out.println("-----reduce(Optional T)2---");
Stream<Double> salaryStream2 = employees.stream().map(Employee::getSalary);
Optional<Double> salarySum2 = salaryStream2.reduce((a,b) -> (a+b) );
System.out.println(salarySum2);
}
}
3. 收集测试
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
/**
* 收集测试
* @author CharlieLiang
*
*/
public class StreamAPITest5 {
@Test
public void test1() {
// collect(Collector c) -- 将流转化为其他形式。接收一个Collector接口的实现,
// 用于给Stream中元素做汇总的方法
//练习:查找工资大于6000的员工,结果返回一个List或Set
System.out.println("---toList----");
List<Employee> employees = EmployeeData.getEmployee();
List<Employee> empList = employees.stream().filter( e -> e.getSalary()>6000).collect(Collectors.toList());
empList.forEach(System.out::println);
System.out.println("---toSet----");
Set<Employee> empSet = employees.stream().filter( e -> e.getSalary()>6000).collect(Collectors.toSet());
empSet.forEach( i -> System.out.println(i));
}
}
Optional类的使用
介绍
Optional类: 为了在程序中避免出现空指针异常而创建的
常用的方法 : ofNullable(T t)
ofElse(T t)
数据准备
girl类
public class Girl {
private String name;
public Girl(String name) {
this.name = name;
}
public Girl() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Girl [name=" + name + "]";
}
}
Boy类
public class Boy {
private Girl girl;
public Boy(Girl girl) {
this.girl = girl;
}
public Boy() {
}
public Girl getGirl() {
return girl;
}
public void setGirl(Girl girl) {
this.girl = girl;
}
@Override
public String toString() {
return "Boy [girl=" + girl + "]";
}
}
测试类
import java.util.Optional;
import org.junit.jupiter.api.Test;
/**
* Optional类: 为了在程序中避免出现空指针异常而创建的
* 常用的方法 : ofNullable(T t)
* ofElse(T t)
* @author CharlieLiang
*
*/
public class OptionTest {
/**
* Option.of(T t): 创建一个Optional实例,t必须非空
* Optional.empty(): 创建一个空的Optional实例
* Optional.ofNullable(T t): t可以为null
*/
@Test
public void test1() {
Girl girl = new Girl();
Optional<Girl> optionalGirl = Optional.of(girl);
System.out.println(optionalGirl);
}
// ----------------------------
@Test
public void test2() {
Girl girl = new Girl();
Optional<Girl> optionalGirl = Optional.ofNullable(girl);
System.out.println(optionalGirl);
System.out.println("---------");
Girl girl2 = null;
Optional<Girl> optionalGirl2 = Optional.ofNullable(girl2);
System.out.println(optionalGirl2);
System.out.println("--------");
//orElse(T t1) : 如果当前的Optional内部封装的t是非空的,则返回内部的t
// 如果内部的t是空的,则返回orElse() 方法中的参数t1
Girl girl3 = optionalGirl2.orElse( new Girl("小梅"));
System.out.println(girl3);
}
// -----------------------------------
public String getGirlName(Boy boy) {
return boy.getGirl().getName();
}
@Test
public void test3() {
Boy boy = new Boy();
String girlName = getGirlName(boy);
System.out.println(girlName);
}
// ----------------------------------
// 优化以后的版本
public String getGirlName2(Boy boy) {
if(boy != null ) {
Girl girl=boy.getGirl();
if(girl != null) return girl.getName();
}
return null;
}
@Test
public void test4() {
Boy boy = new Boy();
String girlName = getGirlName2(boy);
System.out.println(girlName);
}
// ------------------------------------
// 使用Optinal类getGirlName():
public String getGirlName3(Boy boy) {
Optional<Boy> boyOptional = Optional.ofNullable(boy);
// 此时boy2一定非空
Boy boy2 = boyOptional.orElse(new Boy(new Girl("大梅")));
Girl girl=boy2.getGirl();
Optional<Girl> girlOptional = Optional.ofNullable(girl);
// girl2 一定非空
Girl girl2 = girlOptional.orElse(new Girl("小娟"));
return girl2.getName();
}
@Test
public void test5() {
Boy boy = null;
String girlName = getGirlName3(boy);
System.out.println(girlName);
System.out.println("---------");
Boy boy2 = new Boy();
String str= getGirlName3(boy2);
System.out.println(str);
System.out.println("----------");
Boy boy3 = new Boy( new Girl("陈老师") );
String strChen= getGirlName3(boy3);
System.out.println(strChen);
}
}
运行结果:
test1
test2
test3
NullPointerException
test4
test5