Java8新特性Stream的常见用法(java中stream用法)
Stream简介
Stream流是java 8 中新引入的特性,用来处理集合中的数据,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。
Stream不是数据结构,也不保存数据,它是有关算法和计算的,更像一个高级版本的迭代器Iterator。原始版本的 Iterator,只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“判断是否包含某个字符”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。
Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,可以很方便地写出高性能的并发程序。
Stream的使用
流操作的类型有三种:
(1)创建流
(2)修改流元素(中间操作,Intermediate Operations)
(3)消费流元素(终端操作,Terminal Operations)
创建流
流有两种:(1)stream() : 创建串行流。(2)parallelStream() : 创建并行流。
并行流的特点就是将一个大任务切分成多个小任务,无序一起执行,当然如果我们需要顺序输出的话可以使用forEachOrdered,速度会比串行流快一些。它通过默认的ForkJoinPool,可能提高你的多线程任务的速度。
(1) 通过Stream.of()将元素转化成流
Stream.of创建流
Stream stream = Stream.of("你", "我", "她");
(2)每个集合都可以通过调用 stream() 方法来产生一个流
//
String [] strArray = new String[] {"a", "b", "c"};
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
//
List list = Arrays.asList(strArray);
stream = list.stream();
//
Set w = new HashSet<>(Arrays.asList(strArray))
stream = w.stream();
使用举例
案例里使用的类
class Person {
private String name; // 姓名
private int salary; // 战斗力
private int age; // 年龄
private String sex; //性别
private String area; // 必杀技
// 构造方法
public Person(String name, int salary, int age,String sex,String area) {
this.name = name;
this.salary = salary;
this.age = age;
this.sex = sex;
this.area = area;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", salary=" + salary +
", age=" + age +
", sex='" + sex + '\'' +
", area='" + area + '\'' +
'}';
}
}
(1) 遍历/匹配(foreach/find/match)
Stream也是支持类似集合的遍历和匹配元素的,只是Stream中的元素是以Optional类型存在的。Optional类是一个可以为null的容器对象,调用get()方法会返回该对象。
@Test
public void streamTest1() {
List personList = new ArrayList();
personList.add(new Person("鸣人", 8900, 18, "1","螺旋丸"));
personList.add(new Person("佐助", 8800, 18, "1","须佐能乎"));
personList.add(new Person("小樱", 7800, 17, "2","治疗术"));
personList.add(new Person("自来也", 8200, 30, "1","通灵术"));
personList.add(new Person("大蛇丸", 9500, 30, "1","八岐大蛇"));
personList.add(new Person("纲手", 7900, 29, "2","百豪之术"));
// 遍历输出符合条件的对象, 战斗力大于8000
personList.stream().filter(person -> person.getSalary() > 8000).forEach(System.out::println);
// 匹配第一个
Optional findFirst = personList.stream().filter(person -> person.getAge() > 18).findFirst();
System.out.println("匹配第一个值:" + findFirst.get());
// 匹配随机一个(适用于并行流)
Optional findAny = personList.parallelStream().filter(person -> person.getAge() > 18).findAny();
System.out.println("匹配随机一个值:" + findAny.get());
// 是否包含符合特定条件 年龄大于20
boolean anyMatch = personList.stream().anyMatch(person -> person.getAge() > 20);
System.out.println("是否存在年龄大于20的:" + anyMatch);
}
运行结果:
(2)筛选(filter)
筛选,是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。
@Test
public void streamTest2() {
List personList = new ArrayList();
personList.add(new Person("鸣人", 8900, 18, "1","螺旋丸"));
personList.add(new Person("佐助", 8800, 18, "1","须佐能乎"));
personList.add(new Person("小樱", 7800, 17, "2","治疗术"));
personList.add(new Person("自来也", 8200, 30, "1","通灵术"));
personList.add(new Person("大蛇丸", 9500, 30, "1","八岐大蛇"));
personList.add(new Person("纲手", 7900, 29, "2","百豪之术"));
//筛选出所有战斗力大于8000的
List list = personList.stream().filter(person -> person.getSalary() > 8000).collect(Collectors.toList());
System.out.println("战斗力大于8000的值:" + list);
}
运行结果:
(3)聚合(max/min/count/sum)
max、min、count、sum这些字眼你一定不陌生,没错,在mysql中我们常用它们进行数据统计。Java stream中也引入了这些概念和用法,极大地方便了我们对集合、数组的数据统计工作。
@Test
public void streamTest3() {
List personList = new ArrayList();
personList.add(new Person("鸣人", 8900, 18, "1","螺旋丸"));
personList.add(new Person("佐助", 8800, 18, "1","须佐能乎"));
personList.add(new Person("小樱", 7800, 17, "2","治疗术"));
personList.add(new Person("自来也", 8200, 30, "1","通灵术"));
personList.add(new Person("大蛇丸", 9500, 31, "1","八岐大蛇"));
personList.add(new Person("纲手", 7900, 29, "2","百豪之术"));
//获取年龄最大的
Optional max = personList.stream().max(Comparator.comparing(Person::getAge));
System.out.println("年龄最大的是:" + max.get());
//获取战斗力最小的
Optional min = personList.stream().min(Comparator.comparing(Person::getSalary));
System.out.println("战斗力最小的是:" + min.get());
//计算战斗力大于8000的有几个人
long count = personList.stream().filter(person -> person.getSalary() > 8000).count();
System.out.println("战斗力大于8000的人数是:" + count);
//计算总年龄是多少
int sum = personList.stream().mapToInt(person -> person.getAge()).sum();
System.out.println("总年龄是是:" + sum);
}
运行结果:
(4)排序(sorted)
stream中有两种排序:
sorted():自然排序,流中元素需实现Comparable接口
sorted(Comparator com):自定义排序,自定义Comparator排序器
@Test
public void streamTest4() {
List personList = new ArrayList();
personList.add(new Person("鸣人", 8900, 18, "1","螺旋丸"));
personList.add(new Person("佐助", 8800, 18, "1","须佐能乎"));
personList.add(new Person("小樱", 7800, 17, "2","治疗术"));
personList.add(new Person("自来也", 8200, 30, "1","通灵术"));
personList.add(new Person("大蛇丸", 9500, 31, "1","八岐大蛇"));
personList.add(new Person("纲手", 7900, 29, "2","百豪之术"));
//按战斗力升序排序(自然排序)
List newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).collect(Collectors.toList());
System.out.println("按战斗力升序排序:" + newList);
//按战斗力降序排序(自然排序)
List newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed()).collect(Collectors.toList());
System.out.println("按战斗力降序排序:" + newList2);
// 先按年龄再按战斗力排序(自定义排序 降序)
List newList3 = personList.stream().sorted((p1, p2) -> {
if (p1.getAge() == p2.getAge()) {
return p2.getSalary() - p1.getSalary();
} else {
return p2.getAge() - p1.getAge();
}
}).collect(Collectors.toList());
System.out.println("先按年龄再按战斗力:" + newList3);
}
运行结果:
(5) 映射(map/flatMap)
映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap:
- map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
- flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
@Test
public void streamTest5() {
List personList = new ArrayList();
personList.add(new Person("鸣人", 8900, 18, "1","螺旋丸"));
personList.add(new Person("佐助", 8800, 18, "1","须佐能乎"));
personList.add(new Person("小樱", 7800, 17, "2","治疗术"));
personList.add(new Person("自来也", 8200, 30, "1","通灵术"));
personList.add(new Person("大蛇丸", 9500, 31, "1","八岐大蛇"));
personList.add(new Person("纲手", 7900, 29, "2","百豪之术"));
//将人物和必杀技组合,
List strList = personList.stream().map(person -> person.getName() + "-->" + person.getArea()).collect(Collectors.toList());
System.out.println("人物和必杀技组合:" + strList);
}
运行结果:
(6)归约(reduce)
归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。
@Test
public void streamTest6() {
List personList = new ArrayList();
personList.add(new Person("鸣人", 8900, 18, "1","螺旋丸"));
personList.add(new Person("佐助", 8800, 18, "1","须佐能乎"));
personList.add(new Person("小樱", 7800, 17, "2","治疗术"));
personList.add(new Person("自来也", 8200, 30, "1","通灵术"));
personList.add(new Person("大蛇丸", 9500, 31, "1","八岐大蛇"));
personList.add(new Person("纲手", 7900, 29, "2","百豪之术"));
//求战斗力总和 方式1
Integer sum = personList.stream().map(Person::getSalary).reduce((x,y) -> x + y).get();
System.out.println("战斗力总和(方式1):" + sum);
//求战斗力总和 方式2
Integer sum2 = personList.stream().map(Person::getSalary).reduce(Integer::sum).get();
System.out.println("战斗力总和(方式2):" + sum2);
//求战斗力总和 方式3
Integer sum3 = personList.stream().map(Person::getSalary).reduce(0,Integer::sum);
System.out.println("战斗力总和(方式3):" + sum3);
//求年龄的乘积
Integer product = personList.stream().map(Person::getAge).reduce((x,y) -> x * y).get();
System.out.println("年龄的乘积:" + product);
//求战斗力最大的值
Integer max = personList.stream().map(Person::getSalary).reduce(1,Integer::max);
System.out.println("斗力最大的值:" + max);
}
运行结果:
(7)收集(collect)
收集,可以说是内容最繁多、功能最丰富的部分了。从字面上去理解,就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。主要依赖
java.util.stream.Collectors类内置的静态方法。
(8)归集(toList/toSet/toMap)
因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList、toSet和toMap是比较常见的用法
@Test
public void streamTest7() {
List personList = new ArrayList();
personList.add(new Person("鸣人", 8900, 18, "1", "螺旋丸"));
personList.add(new Person("佐助", 8800, 18, "1", "须佐能乎"));
personList.add(new Person("小樱", 7800, 17, "2", "治疗术"));
personList.add(new Person("自来也", 8200, 30, "1", "通灵术"));
personList.add(new Person("大蛇丸", 9500, 31, "1", "八岐大蛇"));
personList.add(new Person("纲手", 7900, 29, "2", "百豪之术"));
//必杀技list集合
List list = personList.stream().map(person -> person.getArea()).collect(Collectors.toList());
System.out.println("必杀技集合toList:" + list);
//大于18的年龄set集合
Set set = personList.stream().filter(person -> person.getAge() > 18).map(Person::getAge).collect(Collectors.toSet());
System.out.println("大于18的年龄集合toSet:" + set);
//战斗力大于8000的map集合 (写法1)
Map, Person> map = personList.stream().filter(p -> p.getSalary() > 8000)
.collect(Collectors.toMap(Person::getName, p -> p));
System.out.println("战斗力大于8000的集合toMap:" + map);
//战斗力大于8000的map集合 (写法2)
Map, Person> map2 = personList.stream().filter(p -> p.getSalary() > 8000)
.collect(Collectors.toMap(Person::getName, Function.identity()));
System.out.println("战斗力大于8000的集合toMap:" + map2);
}
运行结果:
总结
好了,以上就是我总结的Stream的常见用法,感谢大家的阅读,如果有什么疑问或者建议,欢迎评论区留下你的独到见解~