stream简介
Java8中的Stream是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作,或者大批量数据操作等操作;Stream不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的。
stream的创建
public static void main(String[] args) {
//通过Collection系列集合通过的stream()或parallelStream()方法生成流
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
//创建串行流
Stream<String> collectionStream = list.stream();
//创建并行流
Stream<String> collectionParallelStream = list.parallelStream();
//通过Arrays中的静态方法stream()获取数组流
Integer[] arrays = new Integer[]{1,2,3};
Stream<Integer> arraysStream = Arrays.stream(arrays);
//通过Stream类中的静态方法of()获取流
Stream<Object> stream = Stream.of(1, "a");
//无限流(可以无限生成数据的流)
/**
* 迭代
* 第一个参数表示初始值,
* 第二个参数是接口是函数,表示生成什么样的数据,
* 本例是生成偶数据
*/
Stream<Integer> iterateStream = Stream.iterate(0, (e) -> e + 2);
//生成
Stream<Double> generateStream = Stream.generate(() -> Math.random());
Stream的操作
Stream的操作有中间操作和终止操作2中类型操作;
中间操作只会处理数据,不会生成结果;
终止操作是终止中间操作并且生成中间操作后的数据。
Stream的中间操作
准备数据
public class User {
private String name;
private Integer age;
private Double money;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public User(String name, Integer age, Double money) {
this.name = name;
this.age = age;
this.money = money;
}
public User() {
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", money=" + money +
'}';
}
/**
* 如果不同时重写equals和hashCode方法,则distinct方法无效
*
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return Objects.equals(getName(), user.getName()) &&
Objects.equals(getAge(), user.getAge());
}
@Override
public int hashCode() {
return Objects.hash(getName(), getAge());
}
}
static List<User> userList = new ArrayList<>();
static {
userList.add(new User("张三",20,1000D));
userList.add(new User("李四",21,2000D));
userList.add(new User("王五",22,3000D));
userList.add(new User("赵六",23,4000D));
userList.add(new User("张三",20,2000D));
}
filter(筛选操作)
public static void main(String[] args) {
/**
* filter(筛选)
* 参数:接收一个接口式函数 ,改函数是进行条件判断的,表示筛选出满足改条件的数据
* 数据会内部迭代,筛选全部数据
*/
Stream<User> userStream = userList.stream().filter(e -> e.getAge() > 22);
//输出筛选后的数据
userStream.forEach(System.out::println);
}
limit(截断流,使其元素不超过给定数量)
public static void main(String[] args) {
/**
* limit:截断流,使其元素不超过给定数量
*/
Stream<User> userStream = userList.stream().limit(3);
//输出筛选后的数据
userStream.forEach(System.out::println);
}
skip
public static void main(String[] args) {
/**
* skip:跳过元素,返回一个舍弃了前n个元素的流;
* 若流中元素不足n个,则返回一个空流;
*
*/
Stream<User> userStream = userList.stream().skip(2);
//输出筛选后的数据
userStream.forEach(System.out::println);
}
limit和skip组合成分页功能
public static void main(String[] args) {
/**
* 使用skip和limit组合成分页
*
*/
Integer page = 0;
Integer rows = 2;
Integer start = page * rows;
if(start > userList.size()){
start = userList.size() - rows;
}
Stream<User> userStream = userList.stream().skip(start).limit(rows);
//输出筛选后的数据
userStream.forEach(System.out::println);
}
filter与limit和skip组合的区别
public static void main(String[] args) {
/**
* filter和limit组合会终止数据的内部迭代,
* 当数据筛选数据个数满足limit的个数时,数据就会终止迭代
*/
Stream<User> limitUserStream = userList.stream().filter(e -> {
System.out.println("1111");
return e.getAge() > 19;
}).limit(1);
//输出筛选后的数据
limitUserStream.forEach(System.out::println);
/**
* filter和skip组合不会终止数据的内部迭代,
* 他是在筛选出所有的数据后,在跳过skip指定的个数
*/
Stream<User> skipUserStream = userList.stream().filter(e -> {
System.out.println("2222");
return e.getAge() > 19;
}).skip(1);
//输出筛选后的数据
skipUserStream.forEach(System.out::println);
}
distinct(去重)
public static void main(String[] args) {
/**
* distinct:去重,当集合数据为类对象时,
* 改对象必须重写hashCode()与equals()方法,
* 否则无法去重
*
*/
//类对象集合
Stream<User> userStream = userList.stream().distinct();
//输出筛选后的数据
userStream.forEach(System.out::println);
//基本数据集合
List<Integer> integerList = new ArrayList<>();
integerList.add(1);
integerList.add(1);
Stream<Integer> distinctInteger = integerList.stream().distinct();
distinctInteger.forEach(System.out::println);
//基本数据集合
List<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("a");
Stream<String> distinctString = stringList.stream().distinct();
distinctString.forEach(System.out::println);
}
map(映射)
public static void main(String[] args) {
/**
* map:接收接口式函数作为参数,
* 该函数会被应用到每个元素上,
* 并将其映射成一个新的元素
*
*/
//获取用户姓名
Stream<String> userNameStream = userList.stream().map(e -> e.getName());
//输出筛选后的数据
userNameStream.forEach(System.out::println);
}
flatMap(拍平映射)
public static void main(String[] args) {
/**
* flatMap:接收接口式函数作为参数,
* 该函数会被应用到每个元素上,
* 并将每个元素换成另一个流,
* 然后把所有流重新连接成一个流其映射成一个新的元素
*
*/
//获取用户姓名中的子的集合
Stream<Character> userNameStream = userList.stream().map(User::getName).flatMap(e ->{
List<Character> list = new ArrayList<>();
for (Character ch : e.toCharArray()){
list.add(ch);
}
return list.stream();
});
userNameStream.forEach(System.out::println);
}
sorted(排序)
public static void main(String[] args) {
public static void main(String[] args) {
/**
* sorted:排序;接受一个接口式函数作为参数,改函数用于指明排序规则
*/
Stream<User> sortedUser = userList.stream().sorted((first, second) -> {
Integer firstAge = first.getAge();
Integer secondAge = second.getAge();
int i = firstAge - secondAge;
if (i == 0) {
String firstName = first.getName();
String secondName = second.getName();
i = firstName.hashCode() - secondName.hashCode();
}
return i;
});
sortedUser.forEach(System.out::println);
}
终止操作
allMatch、anyMatch和noneMatch匹配
public static void main(String[] args) {
/**
* allMatch:全部匹配
* 匹配流中所有元素是否都满足条件;
* 如果都满足条件,则返回true;
* 否则返回false
*/
boolean allMatchFlag = userList.stream().allMatch(e -> e.getAge() == 20);
System.out.println("allMatchFlag:"+allMatchFlag);
/**
* anyMatch:任意匹配
* 匹配流中任意元素是否满足条件;
* 如果有一个元素满足条件,则返回true;
* 否则返回false
*/
boolean anyMatchFlag = userList.stream().anyMatch(e -> e.getAge() == 20);
System.out.println("anyMatchFlag:"+anyMatchFlag);
/**
* noneMatchFlag:都不匹配
* 匹配流中所有元素是否满足条件;
* 如果都不满足条件,则返回true;
* 否则返回false
*/
boolean noneMatchFlag = userList.stream().noneMatch(e -> e.getAge() == 200);
System.out.println("noneMatchFlag:"+noneMatchFlag);
}
findFirst和findAny查找
public static void main(String[] args) {
/**
* findFirst:获取流中第一个元素;
* 串行流和并行流的结果都一样
*/
Optional<User> opFirst = userList.stream().findFirst();
if(opFirst.isPresent()){
User user = opFirst.get();
System.out.println(user);
}
/**
* findAny:获取流中的任意一个元素;
* 串行流最会获取第一个元素,
* 并行流会随机获取任意一个元素
*
*/
for (int i = 0; i < 100; i++){
Optional<User> opAnyFirst = userList.stream().findAny();
if(opAnyFirst.isPresent()){
User user = opAnyFirst.get();
System.out.println(user);
}
}
for (int i = 0; i < 100; i++){
Optional<User> opAnySecond = userList.parallelStream().findAny();
if(opAnySecond.isPresent()){
User user = opAnySecond.get();
System.out.println(user);
}
}
}
count、max和min
public static void main(String[] args) {
//获取流中是总个数
long count = userList.stream().count();
System.out.println("count:"+count);
//获取流中年龄最大的用户
Optional<User> maxOP = userList.stream().max((first, second) -> Double.compare(first.getAge(), second.getAge()));
if(maxOP.isPresent()){
User user = maxOP.get();
System.out.println(user);
}
//获取流中年龄最小的年龄值
Optional<Integer> minOP = userList.stream().map(e -> e.getAge()).min(Double::compare);
if(maxOP.isPresent()){
Integer minAge = minOP.get();
System.out.println(minAge);
}
}
reduce
public static void main(String[] args) {
/**
* reduce:可以将流中的数据结合起来,得到一个值;
* 第一个参数表示初始值,
* 第二个参数是接口式函数,要出来这些数据的逻辑
*/
Double reduce = userList.stream().map(e -> e.getMoney()).reduce(0d, (x, y) -> x + y);
System.out.println(reduce);
/**
* 由于没有指定初始值,所以返回Optional对象
*/
Optional<Double> reduceOp = userList.stream().map(e -> e.getMoney()).reduce(Double::sum);
if(reduceOp.isPresent()){
System.out.println(reduceOp.get());
}
}
collect(收集)
public static void main(String[] args) {
/**
* joining:将收集后的数据所有","路径起来
*/
String str = userList.stream().map(e -> e.getName()).collect(Collectors.joining(","));
System.out.println(str);
/**
* toSet:将收集的数据转成Set集合
*/
Set<String> set = userList.stream().map(e -> e.getName()).collect(Collectors.toSet());
System.out.println(set);
/**
* toCollection:将收集的数据转成HashSet集合
*/
Set<String> hashSet = userList.stream().map(e -> e.getName()).collect(Collectors.toCollection(HashSet::new));
System.out.println(hashSet);
/**
* toMap:将收集的数据转成map集合
* 第一个参数是接口式函数,表示生成key值策略;
* 第二个参数是接口式函数,表示生成value的策略;
* 第三个参数是接口是函数,表示当key重复了,如何生成key-value的策略,
* 此处表示使用新的value退回以前的value
*/
Map<String, Double> map = userList.stream().collect(Collectors.toMap(e -> e.getName(), e -> e.getMoney(),(oldVal, currVal) -> currVal));
System.out.println(map);
}
计算
public static void main(String[] args) {
/**
* counting:计算数据数据的总个数
*/
Long count = userList.stream().collect(Collectors.counting());
System.out.println("count:"+count);
/**
* summingDouble:求和
*/
Double sum = userList.stream().collect(Collectors.summingDouble(e -> e.getMoney()));
System.out.println("sum:"+sum);
/**
* averagingDouble:求平均值
*/
Double average = userList.stream().collect(Collectors.averagingDouble(e -> e.getMoney()));
System.out.println("average:"+average);
/**
* 获取工资最高的用户
*/
Optional<User> maxOp = userList.stream().collect(Collectors.maxBy((first, second) -> Double.compare(first.getMoney(), second.getMoney())));
if(maxOp.isPresent()){
System.out.println("maxUser:"+maxOp.get());
}
/**
* 获取最低工资值
*/
Optional<Double> minOp = userList.stream().map(e -> e.getMoney()).collect(Collectors.minBy(Double::compare));
if(minOp.isPresent()){
System.out.println("min"+minOp.get());
}
System.out.println("----------------------");
/**
* summarizingDouble:总结
*/
DoubleSummaryStatistics dss = userList.stream().collect(Collectors.summarizingDouble(User::getMoney));
System.out.println("max:"+dss.getMax());
System.out.println("count:"+dss.getCount());
System.out.println("min:"+dss.getMin());
System.out.println("average:"+dss.getAverage());
System.out.println("sum:"+dss.getSum());
}
分组
public static void main(String[] args) {
/**
* 单一分组
*/
Map<Integer, List<User>> groupCollect = userList.stream().collect(Collectors.groupingBy(User::getAge));
System.out.println(groupCollect);
/**
* 自定义分组
*/
Map<String, Map<String, List<User>>> zdyGroupCollect = userList.stream().collect(Collectors.groupingBy(User::getName, Collectors.groupingBy(e -> {
if (e.getAge() <= 10) {
return "儿童";
} else if (e.getAge() <= 18) {
return "青年";
} else {
return "非青年";
}
})));
System.out.println(zdyGroupCollect);
/**
* 多级分组
*/
Map<String, Map<Integer, List<User>>> moreGroupCollect = userList.stream().collect(Collectors.groupingBy(User::getName, Collectors.groupingBy(User::getAge)));
System.out.println(moreGroupCollect);
}
分区
public static void main(String[] args) {
Map<Boolean, List<User>> collect = userList.stream().collect(Collectors.partitioningBy(e -> e.getMoney() > 2000));
System.out.println(collect);
}
串行流与并行流
public static void main(String[] args) {
/**
* sequential:改方法可以就流转换成串行流(相当于集合创建的串行流),
* 该流只会使用一个线程去执行;
* parallel:改方法可以就流转换成并行流(相当于集合创建的并行流),
* 该流会调用多个线程去执行。
*/
//串行流
Instant sequentialStart = Instant.now();
long sequentialResult = LongStream.rangeClosed(0, 100000000000l).sequential().reduce(0, Long::sum);//
Instant sequentialEnd = Instant.now();
System.out.println("串行流耗时:"+Duration.between(sequentialStart, sequentialEnd).toMillis());
System.out.println(sequentialResult);
//并行流
Instant parallelStart = Instant.now();
long parallelResult = LongStream.rangeClosed(0, 100000000000l).parallel().reduce(0, Long::sum);//4891
Instant parallelEnd = Instant.now();
System.out.println("并行流耗时:"+Duration.between(parallelStart, parallelEnd).toMillis());
System.out.println(parallelResult);
}