前言
Java8中有二个最为重要的改变。第一个是Lambda 表达式,另一个则是Strean API(Java.util.stream.*)Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似与使用SQL执行的数据库查询。也可以使用Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
什么是Stream(流)?
是数据的渠道,用于操作数据源(集合、数组等)所生成的元素序列。(集合讲的是数据,流讲的是计算)
注意:
1.Stream 自己不会存储元素
2.Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
3.Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
Stream 操作的三个步骤
1.创建Stream:一个数据源(集合,数组),获取一个流
//1.创建Stream
@Test
public void test1(){
//1.可以通过Collection 系列的集合提供的Stream() 或 parallelStream()
List<String> list = new ArrayList<>();
list.add("你好");
Stream<String> stream1 = list.stream();
//2.通过Arrays中的静态方法stream()获取数组流
UserOrder[] userOrders = new UserOrder[10];
Stream<UserOrder> stream = Arrays.stream(userOrders);
//3.通过Stream 类中的静态方法of()
Stream<String> stream3 = Stream.of("aa","bb","cc");
//4.创建无限流
//迭代,取前五个
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
stream4.limit(5).forEach(System.out::println);
//生成无数随机,取前5
Stream.generate(() -> Math.random()).limit(5).forEach(System.out::println);
}
2.中间操作(一个中间操作链,对数据源的数据进行处理)
/**
* 筛选与切片
*
* filter --接收Lambda,从流中排除某些元素
* limit--截断流,使元素不超过给定数量
* skip(n) -- 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不满足n个,则返回一个空流。与limit(n)互补
* distinct -- 筛选 ,通过流所生成的hashCode() 和 equals() 去除重复元素。
*/
@Test
public void test2(){
List<User> users = Arrays.asList(
new User(18, "张三", "手机"),
new User(20, "李四", "面包"),
new User(20, "赵武", "矿泉水"),
new User(15, "球球", "鸡腿"),
new User(16, "球球", "鸡腿")
);
//中间操作:不会执行任何操作
System.out.println("----------------filter--接收Lambda,从流中排除某些元素-------------------");
//单条件过滤
Stream<User> userStream1 = users.stream().filter((e) -> e.getAge() > 18);
//多条件过滤1
Stream<User> userStream2 = users.stream().filter((e) -> e.getAge() > 18).filter((e) -> e.getShop().equals("面包"));
//多条件过滤2
Stream<User> userStream3 = users.stream().filter((e) -> e.getAge() > 18 && e.getShop().equals("面包"));
//终止操作:全部执行操作
userStream1.forEach(System.out::println);
System.out.println("----------------limit--截断流,使元素不超过给定数量---------------------");
Stream<User> userStream4 = users.stream().limit(3);
userStream4.forEach(System.out::println);
System.out.println("-------skip(n) --跳过元素,返回一个扔掉了前n个元素的流。若流中元素不满足n个,则返回一个空流。与limit(n)互补--------");
Stream<User> userStream5 = users.stream().skip(3);
userStream5.forEach(System.out::println);
System.out.println("---------distinct -- 筛选 ,通过流所生成的hashCode() 和 equals() 去除重复元素。-----------");
//如果需要指定去重中不需要那么多则把实体类中hashCode()和equals()方法中的参数去除即可
//方法1
Stream<User> userStream6 = users.stream().distinct();
userStream6.forEach(System.out::println);
System.out.println("----------------------方法2----------------------------");
//方法2
List<User> userStream7 = users.stream()
.collect(
Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(e ->
e.getShop() + e.getName()
))),
ArrayList::new
)
);
System.out.println(userStream7);
}
/**
* 映射
* map--接收Lambda,讲元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,
* 并将其映射成一个新的元素。
* flatMap -- 接收一个函数作为参数,将流中的每个值都被换成另一个流,然后把所有流连成一个流
*/
@Test
public void test3(){
List<String> list = Arrays.asList("a","b","c");
List<User> userList = Arrays.asList(
new User(18, "张三", "手机"),
new User(20, "李四", "面包"),
new User(20, "赵武", "矿泉水"),
new User(15, "球球", "鸡腿"),
new User(16, "球球", "鸡腿")
);
list.stream().map((e) -> e.toUpperCase()).forEach(System.out::println);
System.out.println("--------获取实体对象的某一个值--------");
userList.stream().map(User::getShop).forEach(System.out::println);
}
/**
* 排序
* sorted() --自然排序
* sorted(Comparator com) -- 定制排序
*/
@Test
public void test7(){
List<String> list = Arrays.asList("c","a","g","b");
list.stream().sorted().forEach(System.out::println);
List<User> userList = Arrays.asList(
new User(18, "张三", "手机"),
new User(20, "李四", "面包"),
new User(20, "赵武", "矿泉水"),
new User(15, "球球", "鸡腿"),
new User(16, "球球", "鸡腿")
);
userList.stream().sorted((e1,e2) -> {
if(e1.getAge().equals(e2.getAge())){
return e1.getName().compareTo(e2.getName());
}else{
return e1.getAge().compareTo(e2.getAge());
}
}).forEach(System.out::println);
}
3.终止操作(终端操作):一个终止操作,执行中间操作链,并产生结果
/**
* 查找与匹配
* allMatch --检查是否匹配所有元素
* anyMatch --检查是否至少匹配一个元素
* noneMach --检查是否没有匹配所有元素
* findFirst -- 返回第一个元素
* findAny -- 返回当前流中的任意元素
* count -- 返回流中元素的总个数
* max -- 返回流中的最大值
* min -- 返回流中的最小值
*/
@Test
public void test8(){
List<User> userList = Arrays.asList(
new User(18, "张三", "手机", User.Status.BUSY),
new User(20, "李四", "面包",User.Status.VOCATION),
new User(20, "赵武", "矿泉水",User.Status.BUSY),
new User(15, "球球", "鸡腿",User.Status.FREE),
new User(16, "球球", "鸡腿",User.Status.FREE)
);
System.out.println("------------allMatch检查是否匹配所有元素--------------");
boolean y = userList.stream().allMatch((e)-> e.getStatus().equals(User.Status.BUSY));
System.out.println(y);
System.out.println("------------anyMatch检查是否至少匹配一个元素--------------");
boolean y2 = userList.stream().anyMatch((e) -> e.getStatus().equals(User.Status.BUSY));
System.out.println(y2);
System.out.println("------------ noneMach检查是否没有匹配所有元素--------------");
boolean y3 = userList.stream().noneMatch((e) -> e.getStatus().equals(User.Status.BUSY));
System.out.println(y3);
System.out.println("------------ findFirst返回第一个元素--------------");
Optional<User> op = userList.stream().sorted((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())).findFirst();
System.out.println(op.get());
System.out.println("------------ findAny返回当前流中的任意元素--------------");
Optional<User> op2 = userList.stream().filter((e) -> e.getStatus().equals(User.Status.FREE)).findAny();
System.out.println(op2);
System.out.println("------------ count返回流中元素的总个数--------------");
Long count = userList.stream().count();
System.out.println(count);
System.out.println("------------ max返回流中的最大值--------------");
Optional<User> op3 = userList.stream().max((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()));
System.out.println(op3);
System.out.println("------------ min返回流中的最小值--------------");
Optional<Integer> op4 = userList.stream().map(User::getAge).min(Integer::compare);
System.out.println(op4.get());
}
归约与收集
/**
* 归约
* reduce(T identity, BinaryOperator) --可以将流中元素反复结合起来,得到一个值。
*/
@Test
public void test(){
List<User> userList = Arrays.asList(
new User(18, "张三", "手机", User.Status.BUSY),
new User(20, "李四", "面包",User.Status.VOCATION),
new User(20, "赵武", "矿泉水",User.Status.BUSY),
new User(15, "球球", "鸡腿",User.Status.FREE),
new User(16, "球球", "鸡腿",User.Status.FREE)
);
List<Integer> list = Arrays.asList(1, 2, 3, 4);
Integer sum = list.stream().reduce(0,(x, y) -> x+y);
System.out.println(sum);
System.out.println("-------计算总和-------");
Optional<Integer> op = userList.stream().map(User::getAge).reduce(Integer::sum);
System.out.println(op.get());
/**
* 收集
* collect--将流转换为其他形式,接收一个collector接口的实现,用于给Stream中元素做汇总的方法。
* Collector接口中方法的实现决定了如何对流执行收集(如收集到List、Set、Map)。
* Collected实用类提供了很多静态方法,可以方便地创建常见收集器实例。
*/
System.out.println("---------收集到List类型之中-------------");
List<String> names = userList.stream().map(User::getName).collect(Collectors.toList());
System.out.println(names);
System.out.println("----------Set----------");
Set<String> set = userList.stream().map(User::getName).collect(Collectors.toSet());
System.out.println(set);
System.out.println("------------指定容器---------------");
HashSet<String> hashSet = userList.stream().map(User::getName).
collect(Collectors.toCollection(HashSet::new));
System.out.println(hashSet);
ArrayList<String> arrayList = userList.stream().map(User::getName).
collect(Collectors.toCollection(ArrayList::new));
System.out.println(arrayList);
System.out.println("----------总数--------");
Long count = userList.stream().collect(Collectors.counting());
System.out.println(count);
System.out.println("----------平均值--------");
Double avg = userList.stream().collect(Collectors.averagingDouble(User::getAge));
System.out.println(avg);
System.out.println("----------总和--------");
Double sums = userList.stream().collect(Collectors.summingDouble(User::getAge));
System.out.println(sums);
System.out.println("----------最大值--------");
Optional<User> users = userList.stream().collect(
Collectors.maxBy((e1, e2) -> Double.compare(e1.getAge(), e2.getAge())));
System.out.println(users.get());
System.out.println("----------最小值--------");
Optional<Integer> min = userList.stream().map(User::getAge).
collect(Collectors.minBy(Integer::compare));
System.out.println(min.get());
System.out.println("----------分组--------");
Map<User.Status, List<User>> map = userList.stream().collect(
Collectors.groupingBy(User::getStatus));
System.out.println(map);
System.out.println("----------多级分组--------");
Map<User.Status,Map<String, List<User>>> map2 = userList.stream().
collect(Collectors.groupingBy(User::getStatus, Collectors.groupingBy((e) -> {
if (((User) e).getAge() <= 18){
return "未成年";
}else{
return "成年";
}
})));
System.out.println(map2);
System.out.println("----------分区:满足条件地在一个区,不满足在一个区--------");
Map<Boolean,List<User>> map3 = userList.stream().
collect(Collectors.partitioningBy((e) -> e.getAge() <= 18));
System.out.println(map3);
System.out.println("----------连接字符串--------");
String str = userList.stream().map(User::getName).
collect(Collectors.joining(",","这是开头","这是结尾"));
System.out.println(str);
}