Java 8 中有两大最为重要的改变。第一个是Lambda表达式;另一个则是Stream API(java.util.stream.*).
Stream 是Java8 中处理集合的关键抽象概念,他可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用SQL 执行的数据库查询。也可以使用Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
什么是Stream
流(Stream)到底是什么呢?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,流讲的是计算!
注意:
①Stream 自己不会存储元素
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新的Stream
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Stream的操作三个步骤
- 创建Stream
一个数据源(如:集合、数组),获取一个流 - 中间操作
一个中间操作链,对数据源的数据进行处理 - 终止操作(终端操作)
一个终止操作,执行中间操作链,并产生结果
一、创建
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
import org.junit.Test;
import com.it.entity.Employee;
/*
*
* 一、Stream的三个操作步骤
* 1、创建Stream
*
* 2、中间操作
*
* 3、终止操作(终端操作)
*
*/
public class TestStreamAPI1 {
//创建Stream
@Test
public void test1() {
//1、可以通过Collection 系列集合提供的stream()或者 paralleStream()
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//2、通过Arrays中的静态方法stream()获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
//3、通过Stream 类中的静态方法of()
Stream<String> stream3 = Stream.of("aa","bb","cc");
//4、创建无限流
//迭代
Stream<Integer> stream4 = Stream.iterate(0,(x) -> x+2);
stream4.limit(10).forEach(System.out::println);
//生成
Stream.generate(()-> Math.random())
.limit(5)
.forEach(System.out::println);
}
}
二、Stream的中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作是一次性全部处理,称为"惰性求值"。
static List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",38,5555.99),
new Employee("王五",18,6666.66),
new Employee("赵六",18,3333.33),
new Employee("田七",18,7777.77)
);
//中间操作
/*
*
* 筛选与切片
* filter -- 接收Lanmbda , 从流中排除某些元素
* limit -- 截断流,使其元素不超过给定数量
* skip(n) -- 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流,与limit(n) 互补
* distinct -- 筛选,通过Loi所生成的元素的hashCode() 和 equals () 去除重复元素
*
*/
//内部迭代
@Test
public void test2() {
//中间操作,不会执行任何操作
Stream<Employee> stream1 = employees.stream()
.filter(e->{
System.out.println("Stream API 的中间操作");
return e.getAge() > 35;
});
//终止操作:一次性执行全部内容,即"惰性求值"
stream1.forEach(System.out::println);
}
//外部迭代
@Test
public void test(){
Iterator<Employee> it = employees.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
@Test
public void test3() {
employees.stream()
.filter(e -> e.getSalary() > 5000)
.limit(2)
.forEach(System.out::println);
}
@Test
public void test4() {
employees.stream()
.filter(e -> e.getSalary() > 5000)
.skip(2)
.limit(2)
.forEach(System.out::println);
}
重写hsahcode 与 equals 方法
map
/**
* 映射
*
* map-- 接收Lambda,将元素转换成其他形式提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
*
* flatMap -- 接收一个函数作为参数,将流中的每个值都换成一个流,然后把所有流连成一个流
*
*/
@Test
public void test5() {
List<String> list = Arrays.asList("aa","bb","cc","dd");
//map
list.stream().map(String::toUpperCase)
.forEach(System.out::println);
System.out.println("-------------");
employees.stream()
.map(emp->emp.getName())
.forEach(System.out::println);
System.out.println("------flatMap-------");
//faltMap
Stream<Stream<Character>> stream = list.stream()
.map(TestStreamAPI1::filterCharacter);
stream.forEach(System.out::println); //打印的是流
System.out.println("-------------");
Stream<Character> flatMap = list.stream()
.flatMap(TestStreamAPI1::filterCharacter);
flatMap.forEach(System.out::println); // a,a,b,b,c,c
}
public static Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for (Character character : str.toCharArray()) {
list.add(character);
}
return list.stream();
}
排序
/**
* 排序
*
* sort() -- 自然排序(Compatable)
*
* sort(Comparator com) -- 定制排序(Comparator)
*
*/
@Test
public void test7() {
List<String> list = Arrays.asList("ccc","bbb","ddd","aaa");
list.stream()
.sorted()
.forEach(System.out::println);
System.out.println("------------");
employees.stream()
.sorted((e1,e2) ->{
if(e1.getAge() == e2.getAge()) {
return e1.getName().compareTo(e2.getName());
}else {
return Integer.compare(e1.getAge(),e2.getAge());
}
}).forEach(System.out::println);
}
终止操作
static List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.99,Status.FREE),
new Employee("李四",58,5555.99,Status.BUSY),
new Employee("王五",26,6666.66,Status.VOCATION),
new Employee("赵六",36,3333.33,Status.FREE),
new Employee("田七",12,7777.77,Status.BUSY)
);
/*
* 查找与匹配
*
* allMatch -- 检查是否匹配所有元素
* anyMatch -- 检查是否至少匹配一个元素
* noneMatch -- 检查是否没有匹配所有元素
*
* findFirst -- 返回第一个元素
* findAny -- 返回当前流中的任意元素
*
* count -- 返回流中元素的总个数
* max -- 返回流中的最大值
* min -- 返回流中的最小值
*
*/
@Test
public void test1() {
boolean b1 = employees.stream()
.allMatch(e->e.getStatus().equals(Status.BUSY));
System.out.println(b1);
boolean b2 = employees.stream()
.anyMatch(e->e.getStatus().equals(Status.BUSY));
System.out.println(b2);
boolean b3 = employees.stream()
.noneMatch(e->e.getStatus().equals(Status.BUSY));
System.out.println(b3);
Optional<Employee> op = employees.stream()
.sorted((e1,e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(op.get());
Optional<Employee> op2 = employees.parallelStream()
.filter(e->e.getStatus().equals(Status.BUSY))
.findAny();
System.out.println(op2.get());
}
@Test
public void test2() {
long count = employees.stream()
.count();
System.out.println(count);
Optional<Employee> op1 = employees.stream()
.max((e1,e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(op1.get());
Optional<Double> op2 = employees.stream()
.map(Employee::getSalary)
.min(Double::compareTo);
System.out.println(op2.get());
}
归约
/*
*
* 归约
* reduce(T identity,BinatuOperator) / reduce(BinaryOperator) -- 可以将流中的元素反复结合起来,得到一个值。
*
*/
@Test
public void test3() {
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
Integer sum = list.stream()
.reduce(0,(x,y)-> x+y);
System.out.println(sum);
/*
开始 x = 0,y = 1
x =1 ,y=2
x=3 ,y=3
x=6 ,y=4
...
*/
Optional<Double> op = employees.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(op.get());
}
收集
- 分组
练习
第一题
第二题 数一数 流中的数量
第三题