一、简介
Java8 API添加了一个新的抽象称为流 Stream ,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流,流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
Stream(流)是一个来自数据源的元素队列并支持聚合操作
- 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源 流的来源。 可以是集合,数组等。
- 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等
Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。
二、Stream的操作三个步骤
- 创建Stream
一个数据源(如:集合、数组),获取一个流 - 中间操作
一个中间操作链,对数据源的数据进行处理 - 终止操作
一个终止操作,执行中间操作链,并产生结果
1.创建Stream
//创建集合
List<String> list=new ArrayList<>();
list.add("aaa");
list.add("bbbb");
list.add("ccccc");
list.add("dddddd");
list.add("eeeeeee");
// 1、可以通过Conllection系列集合提供的顺序流stream()或并行流 parallelStream()
Stream<String> stream = list.stream();
// 2、通过Arrays中的静态方法stream()获取数据流
int[] ints={1,2,3,4,5,6,7,8};
IntStream stream1 = Arrays.stream(ints);
// 3、通过Stream类中的静态方法of()
Stream<String> stream2 = Stream.of("aa", "bb", "cc");
String[] str=new String[10];
Stream<String> str1 = Stream.of(str);
2.Stream的中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理,而在终止操作时一次性全部处理,称为”惰性求值”。
定义一个工具类,用于获取集合和bean类
工具类
public class ListUtil {
public static List<String> getList(){
List<String> list = new ArrayList<>();
list.add("aaaa");
list.add("bbbbbb");
list.add("ddddddd");
list.add("eee");
list.add("ffff");
return list;
}
public static List<Person> getListPerson(){
return Arrays.asList(new Person[]{
new Person("张三",19),
new Person("李四",18)}
);
}
}
Person类
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
[1]筛选和切片
1.filter和limit
//创建集合
List<String> list=new ArrayList<>();
list.add("aaa");
list.add("bbbb");
list.add("ccccc");
list.add("dddddd");
list.add("eeeeeee");
//打印长度超过5的元素
System.out.println("---------打印长度超过5的元素--------");
Stream<String> stream =list.stream();
stream.forEach(t->{
if (t.length()>5)
System.out.println(t);
});
// 将满足条件的那些元素临时存放(假的)一个新的流
Stream<String> stream1 = list.stream().filter(t -> t.length() > 5);
stream1.forEach(t-> System.out.println(t));
//stream1.forEach(t-> System.out.println(t));
System.out.println("=========filter筛选============");
//(1)filter正常写法
list.stream().filter(t->t.length()>6).forEach(t-> System.out.println(t));
//方法引用
list.stream().filter(t->t.length()>5).forEach(System.out::println);
System.out.println("----------limit截取-----------");
// limit截断流,使其元素不超过给定数量
list.stream().limit(3).forEach(System.out::println);
2.skip跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空 流
//获取list集合
List<String> list = ListUtil.getList();
System.out.println("====list集合中的数据为======");
System.out.println(list);
System.out.println("----筛选长度>3的字符串后跳过两个元素----");
//list集合中字符串长度>3的字符串,跳过2个后的到的数据为
list.stream().filter(t->t.length()>3).skip(2).forEach(t-> System.out.println(t));
3.distinct通过流所生产元素的hashCode()和equals()去除重复元素
//获取list集合
List<String> list = ListUtil.getList();
System.out.println("====list集合中的数据为======");
System.out.println(list);
System.out.println("-----使用distinct去重复-----");
//通过流所生产元素的hashCode()和equals()去除重复元素
list.stream().distinct().forEach(System.out::println);
[2] 排序
sorted(Comparable)-自然排序
//获取list集合数据
List<String> list = ListUtil.getList();
System.out.println("====list集合中的数据为======");
System.out.println(list);
//根据字符串长度排序list集合
System.out.println("------根据字符串长度排序list集合-------");
list.stream().sorted((t1,t2)->{
return t1.length()-t2.length();
}).forEach(System.out::println);
//获取泛型为Person对象的list集合
List<Person> listPerson = ListUtil.getListPerson();
System.out.println("----listPerson中的数据为-------");
System.out.println(listPerson);
//根据年龄排序集合中的数据
listPerson.stream().sorted((t1,t2)->{
return t1.getAge()-t2.getAge();
}).forEach(System.out::println);
//只获取成年人的信息
System.out.println("=====成年人的信息为======");
listPerson.stream().filter(t->t.getAge()>=18).forEach(System.out::println);
3.终止操作
[1]查找与匹配
//获取list集合数据
List<String> list = ListUtil.getList();
System.out.println("====list集合中的数据为======");
System.out.println(list);
//allMatch检查是否匹配所有元素
//判断|查看 集合中的元素字符个数是否都大于3个
System.out.println("集合中元素字符个数是否都>3个:"+list.stream().allMatch(t -> t.length() > 3));
//判断|查看 集合中的元素字符个数是否存在大于3个字符的情况
System.out.println("集合中是否有元素大于3个:" + list.stream().anyMatch(t -> t.length() > 3));
//获取list流中第一个元素
Optional<String> first = list.stream().findFirst();
//获取first中的值
System.out.println(first.get());
//获取first中的值,如果没有元素,则返回none
System.out.println(first.orElse("none"));
//findAny为获取任意一个元素,但在普通流中,默认获取的是第一个
System.out.println(list.stream().findAny().get());
//在parallelStream流中,获取的是随机的
System.out.println(list.parallelStream().findAny().get());
//统计字符长度大于3的元素个数
System.out.println("字符串长度>3的元素个数"+list.stream().filter(t -> t.length() > 3).count());
//获取listPerson
List<Person> listPerson = ListUtil.getListPerson();
System.out.println("-----获取listPerson中的元素为------");
System.out.println(listPerson);
System.out.println("返回两参数的较大值"+listPerson.stream().max((t1, t2) -> {
return t1.getAge() - t2.getAge();
}));
[2]收集
List<Employee> emps = Arrays.asList(
new Employee("张三", 18, 3333.33),
new Employee("李四", 38, 4444.44),
new Employee("王五", 50, 5555.55),
new Employee("赵六", 16, 6666.66),
new Employee("田七", 28, 7777.77) );
// 需求:获取当前公司所有员工的姓名添加到集合中
// List-把流中所有元素收集到List中
List<String> nameList = emps.stream().map(Employee::getName).collect(Collectors.toList());
nameList.forEach(System.out::println);
// Set-把流中所有元素收集到Set中,删除重复项
Set<String> nameSet = emps.stream().map(Employee::getName).collect(Collectors.toSet());
nameSet.forEach(System.out::println);
// Map-把流中所有元素收集到Map中,当出现相同的key时会抛异常
Map<String, Integer> empMap = emps.stream().collect(Collectors.toMap(Employee::getName, Employee::getAge));
empMap.forEach((k,v)-> System.out.println(k+" "+v));
// 员工总数
Long collect = emps.stream().collect(Collectors.counting());
System.out.println("员工总数为:"+collect);
// 工资平均数
Double salAvg = emps.stream().collect(Collectors.averagingDouble(Employee::getSal));
System.out.println("平均工资数:"+salAvg);
// 工资总和
DoubleSummaryStatistics salCum = emps.stream().collect(Collectors.summarizingDouble(Employee::getSal));
System.out.println("工资总和为:"+salCum);
// 工资最大值的员工
Optional<Employee> op = emps.stream().collect(Collectors.maxBy((t1, t2) -> Double.compare(t1.getSal(), t2.getSal())));
System.out.println(op.get());