Stream流,可以让你以一种声明的方式处理数据。大致运用于集合类的操作,极大的提高了编程效率和程序可读性。
Stream流是一个来自数据源的元素队列并支持聚合操作,元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
如果是数组的话,可以使用 Arrays.stream()
或者 Stream.of()
创建流;如果是集合的话,可以直接使用 stream()
方法创建流,因为该方法已经添加到 Collection 接口中
stream() − 为集合创建串行流
public static void main(String[] args) {
// 1.数组生成流 Arrays.stream()/Stream.of()
Integer[] arr = new Integer[]{1,2,3,4,5,6,7};
/* 方式一:Arrays.stream(数组)
Stream stream = Arrays.stream(arr); */
// 方式二:Stream.of(数组)
Stream stream = Stream.of(arr);
stream.forEach(System.out::println); // 打印数组中所有元素
// 2.集合生成流. stream()
List list = Arrays.asList(1,2,3,4,5,6,7);
list.stream().forEach(System.out::println); // 打印 list中所有元素
}
执行结果:
forEach()
方法接收的是一个 Consumer(Java 8 新增的一个函数式接口,接受一个输入参数并且无返回的操作)类型的参数,类名 :: 方法名
是 Java 8 引入的新语法。System.out::println 可以看作 lambda表达式 e -> System.out.println(e)
parallelStream() − 为集合创建并行流
public static void main(String[] args) {
List list = Arrays.asList(1,2,3,4,5,6,7);
// parallelStream() 生成一个并行流
list.parallelStream().forEach(System.out::println);
}
执行结果:
通过打印结果发现parallelStream并行流每次执行的结果都不相同,并行流,顾名思义,可以理解为多线程同时执行。
▶ 1. limit 返回条数
limit 方法用于获取指定数量的流。
public static void main(String[] args) {
List list = Arrays.asList(1,2,3,4,5,6,7);
list.stream()
.limit(2) // 获取2条
.forEach(System.out::println);
}
执行结果:以上代码使用 limit 方法打印出 2 条数据
▶ 2. filter 过滤
通过
filter()
方法可以从流中过滤元素
public static void main(String[] args) {
List list = Arrays.asList(1,2,3,4,5,6,7);
list.stream()
.filter(n->n>2) // 筛选出集合中大于2的元素
.filter(n->n%2==0) // 筛选出集合中的偶数
.forEach(System.out::println);
}
执行结果:可以多个filter叠加
filter方法
传入的是一个 Predicate断定型函数接口:接受一个输入参数返回一个布尔值结果,上篇文章已对函数型接口进行了介绍和使用,看不懂此语法的伙伴可以参考:
▶ 3. map转换
用于映射每个元素到对应的结果。可理解为将集合中的元素类型,转换为另一种数据类型,或者是替换集合内部元素打印结果
public static void main(String[] args) {
List list = Arrays.asList("Java","C++","中国");
list.stream()
.map(String::length) //等同map(str->str.length());获取该元素长度
.forEach(System.out::println);
}
执行结果:
示例2:将小写字母转换为大写字母
public static void main(String[] args) {
List list = Arrays.asList("Java","C++","中国");
list.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
}
执行结果:
示例3:提取用户年龄
public static void main(String[] args) {
User u1 = new User(1,"张三",21);
User u2 = new User(2,"李四",22);
List list = Arrays.asList(u1, u2);
list.stream()
.map(u->u.getAge())
.forEach(System.out::println);
}
执行结果:
▶ 4. sorted排序
用于对流进行排序
public static void main(String[] args) {
User u1 = new User(1,"张三",21);
User u2 = new User(2,"李四",22);
List list = Arrays.asList(u1, u2);
list.stream()
.sorted((uu1,uu2)->{return uu2.getAge().compareTo(uu1.getAge());})
.map(u->u.getAge())
.forEach(System.out::println);
}
执行结果:对用户年龄降序输出
▶ 5. distinct 去重
对流中的元素进行去重
public static void main(String[] args) {
List list = Arrays.asList(1,2,2,3,5);
list.stream()
.distinct()
.forEach(System.out::println);
}
执行结果:
▶ 6. reduce 组合
主要作用是把流中的元素组合起来
提供2种用法:
Optional reduce(BinaryOperator accumulator)
没有起始值,只有一个参数,就是运算规则,此时返回Optional
T reduce(T identity, BinaryOperator accumulator)
有起始值,有运算规则,两个参数,此时返回的类型和起始值类型一致。
public static void main(String[] args) {
List list = Arrays.asList(1,1,1);
// 1.没有起始值
Optional optional = list.stream().reduce((a, b) -> a + b);
System.out.println(optional.orElse(0)); // 如果结果为null,则=0
// 2.有起始值,赋初始值为2,并依次累加元素中的值
int sum =list.stream().reduce(2,(a, b) -> a + b);
System.out.println(sum);
}
执行结果:
▶ 7. Collectors 转换流
Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:
public static void main(String[] args) {
// 转换成新流
List list = Arrays.asList("j", "", "a", "v", "","a");
System.out.println("旧集合:"+list);
// 1.转换成新集合
List newList = list.stream()
.filter(string -> !string.isEmpty()) // 过滤为空的元素
.collect(Collectors.toList());
System.out.println("新集合: " + newList);
// 2.转换成TreeSet
TreeSet treeSet = list.stream()
// 等同于Collectors.toList()
.collect(Collectors.toCollection(TreeSet::new));
System.out.println("treeSet:"+treeSet);
// 3.转换成set集合
Set set = list.stream().collect(Collectors.toSet());
System.out.println("set:"+set);
// 4.转换成字符串
String str = list.stream()
.filter(string -> !string.isEmpty()) // 过滤为空的元素
.collect(Collectors.joining("-")); // 分割符
System.out.println("合并字符串: " + str);
}
执行结果:
示例2:分组
public static void main(String[] args) {
// partitioningBy:根据判断的值为true还是false分成2组
List list = Arrays.asList(5, 4, 2, 3, 2,6);
Map> result = list.stream()
.collect(partitioningBy(n -> n>3));
System.out.println(result);
// groupingBy:根据user的年龄分组
User u1 = new User(1,"张三",22);
User u2 = new User(2,"李四",22);
User u3 = new User(3,"王五",23);
List ulist = Arrays.asList(u1, u2, u3, u4);
Map> userResult = ulist.stream()
.collect(Collectors.groupingBy(User::getAge));
System.out.println(userResult);
// groupingBy:根据元素值分组
List numList = Arrays.asList(4, 4, 1, 2);
Map> collect = numList.stream()
.collect(Collectors.groupingBy(n -> n.toString()));
System.out.println(collect);
}
执行结果:同为22岁的有张三和李四,被分为了一组
▶ 8. math匹配
对流中的元素进行匹配,匹配成功返回true,否则false
anyMatch():
只要有一个元素匹配传入的条件,就返回 true。
allMatch():
如果全部元素都匹配传入的条件,则返回 true。有一个不匹配则返回 false
noneMatch():
只要有一个元素匹配传入的条件,则返回 false;全不匹配则返回true
public static void main(String[] args) {
// anyMatch
List list = Arrays.asList("张三", "张婷婷", "王武", "李四");
boolean result = list.stream().anyMatch(n -> n.contains("四"));
System.out.println("任意一个元素包含字符'四':"+result);
// allMatch
boolean result2 = list.stream().allMatch(n -> n.length()>2);
System.out.println("集合元素全部长度>2:"+result2);
// noneMatch
boolean result3 = list.stream().noneMatch(n -> n.startsWith("刘"));
System.out.println("不存在第一个字符为'刘'的元素:"+result3);
}
执行结果: