3-1 Stream流编程-概念
Stream
是一个高级迭代器,不是数据结构,不是集合,不会存放数据,它关注的是怎么把数据高效的处理。
外部迭代和内部迭代
外部迭代:
for 、while
int [] nums = {3,7,4};
int sum = 0;
//外部迭代
for (int num : nums) {
sum += num;
}
System.out.println("sum = " +sum);
内部迭代
int intStream = IntStream.of(nums).sum();
System.out.println("sum = " + intStream);
中间操作/最终操作和惰性求值
//map是中间操作(返回Stream的操作)
//sum是终止操作
int mult =IntStream.of(nums).map(n -> n*2).sum();
System.out.println("multiplication = " +mult);
上面的代码也可以写为:
public static void main(String[] args) {
int mult =IntStream.of(nums).map(StreamDemo3_1::multiplication).sum();
System.out.println("multiplication = " +mult);
}
public static int multiplication(int n){
return n*2;
}
惰性求值就是中间值没用调用的情况下,中间操作不会执行。
IntStream.of(nums).map(StreamDemo3_1::multiplication);
以上程序没有终止操作,中间操作
map
不会被调用。
3-2 流的创建
相关方法 | |
---|---|
集合 | Collection.stream/parallelStream |
数组 | Arrays.stream |
数字Stream | IntStream/LongStream.range/rangeClosed |
数字Stream | Random.ints/longs/soubles |
自己创建 | Stream.generate/iterate |
//从集合中创建流
List<String> list = new ArrayList<>();
list.add("hello");
list.add("my");
list.add("world");
list =list.stream().map( String::toUpperCase).collect(Collectors.toList());
for (String str: list) {
System.out.println(str);
}
//从数组中创建
Arrays.stream(new int []{6,4,5}).sorted().forEach(System.out::println);
//数字Stream
IntStream.of(8,3,5).map(n -> 4*n).sorted().forEach(System.out::println);
//自己产生(无限)流(用limit来限制)
Stream.generate(()-> new Random().nextInt()).limit(10);
3-3 流的中间操作
中间操作分为:
- 无状态操作:当前的操作和其它元素的前后没有关系。
- 有状态操作:结果依赖其它元素。
相关方法 | |
---|---|
无状态操作 | map/mapToXXX |
无状态操作 | flatMap/flatMapToXXX |
无状态操作 | filter |
无状态操作 | peek |
无状态操作 | unordered |
有状态操作 | distinct |
有状态操作 | sorted |
有状态操作 | limit/skip |
map
将A
对象转换成B
对象。mapToXXX
将对象转换为数字,得到对象上的信息(字符串的长度)。flatMap
:A
对象包含B
属性,B
属性是个集合,那么可以使用flatMap
得到最终结果是:得到所偶A
对象里面的所有B
属性的列表。peek
的入参是消费者和终止操作里面的forEach
很像,但是它是中间操作。unordered
并行流才会用到。
String str = "I'm ugly useless person.";
//输出每个单词的长度
Stream.of(str.split(" "))
.map( x -> x.length())
.forEach(System.out::println);
//flatMap A -> B属性(是个集合),最终得到所有A元素里面的所有B属性集合
//IntStream LongStream并不是Stream的子类,所以需要进行装箱boxed
Stream.of(str.split(" "))
.flatMap( n -> n.chars().boxed())
.forEach( n -> System.out.println((char)n.intValue()));
//peek用于debug,是个中间操作,forEach是终止操作
Stream.of(str.split(" "))
.peek(System.out::println)
.forEach(System.out::println);
//limit限制无限流
new Random()
.ints()
.filter(n -> n > 200 && n < 300)
.limit(10)
.forEach(System.out::println);
总结
int
转char
Integer
转int
3-4 流的终止操作
相关方法 | |
---|---|
非短路操作 | forEach/forEachOrdered |
collect/toArray | |
reduce | |
min/max/count | |
短路操作 | findFirst/findAny |
allMatch/anyMatch/noneMatch |
reduce
:减少,将流合并成一个数据。
XXXOrdered
:带Ordered
都是和并行有关。
findAny
:找到任何一个。
String str = "Let life be beautiful like summer flowers and death like autumn leaves.";
//使用并行流
str.chars().parallel().forEach(s -> System.out.print((char) s));
System.out.println();
//使用forEachOrdered保证顺序
str.chars().parallel().forEachOrdered(s -> System.out.print((char) s));
输出结果
ded lkersweilehe loaau nlime b ln ulifattbeautr fikfeeumLe st s.umae v
Let life be beautiful like summer flowers and death like autumn leaves.
在并行时使用
forEach
会导致乱序。
//收集到List
List<String> stringList= Stream.of(str.split(" ")).collect(Collectors.toList());
Optional<String> stringOptional =Stream.of(str.split(" ")).reduce((s1, s2) -> s1 +"|" +s2);
//orElse:如果获取不到则取空
System.out.println(stringOptional.orElse(""));
//赋默认值
String string1 =Stream.of(str.split(" ")).reduce("",(s1, s2) -> s1 +"|" +s2);
System.out.println("串:" + string1);
//计算所有单词长度
int countLength =Stream.of(str.split(" ")).map(s -> s.length()).reduce(0,(n1,n2) -> n1 + n2);
System.out.println("计算所有单词长度" + countLength);
//max的使用
Optional<String> s = Stream.of(str.split(" ")).max((s1,s2) -> s1.length() - s2.length());
System.out.println(s.orElse(""));
3-5 并行流
parallel
IntStream.range(1,100).peek(StreamDemo3_5::debug).count();
public static void debug(int i){
System.out.println("debug" + i);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
输出结果
debug1
debug2
debug3
debug4
每隔三秒输出一个debugi
调用parallel
产生并行流
IntStream.range(1,100).parallel().peek(StreamDemo3_5::debug).count();
输出结果
debug31
debug28
debug7
debug34
debug43
debug16
debug65
debug40
每隔三秒输出八个debugi
先并行后串行处理
IntStream.range(1,100)
//调用parallel产生并行流
.parallel()
.peek(StreamDemo3_5::debug)
//调用sequential产生串行流
.sequential()
.peek(StreamDemo3_5::debug)
.count();
输出结果
debug1
debug1
debug2
debug2
debug3
debug3
每隔三秒输出一个debugi,以上一共用了18s
多次调用parallel/sequential,以最后一次调用为准
并行流使用的线程池:ForkJoinPool.commonPool
IntStream.range(1,100).parallel().peek(StreamDemo3_5::debug).count();
public static void debug(int i){
System.out.println("current thread name = ["+ Thread.currentThread().getName()+"]debug" + i);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
输出结果
current thread name = [ForkJoinPool.commonPool-worker-7]debug87
current thread name = [ForkJoinPool.commonPool-worker-3]debug81
current thread name = [main]debug65
current thread name = [ForkJoinPool.commonPool-worker-1]debug90
current thread name = [ForkJoinPool.commonPool-worker-6]debug78
current thread name = [ForkJoinPool.commonPool-worker-5]debug96
current thread name = [ForkJoinPool.commonPool-worker-4]debug16
current thread name = [ForkJoinPool.commonPool-worker-2]debug31
默认的线程数是当前CPU个数
修改默认的线程数
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism","20");
所有的并行流都使用同一个默认的线程池,就会有阻塞问题,所以要使用自己的线程池
//使用自己的线程池,不使用默认线程池,防止任务被阻塞
ForkJoinPool pool = new ForkJoinPool(10);
pool.submit(() -> IntStream.range(1,100).parallel()
.peek(StreamDemo3_5::debug).count());
pool.shutdown();
输出结果
主函数已经退出,由于当前线程是守护线程,所以也自动退出了
//使用自己的线程池,不使用默认线程池,防止任务被阻塞
ForkJoinPool pool = new ForkJoinPool(10);
pool.submit(() -> IntStream.range(1,100).parallel()
.peek(StreamDemo3_5::debug).count());
pool.shutdown();
//不要让主线程退出,让主线程等待
synchronized (pool){
try {
pool.wait(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
输出结果
current thread name = [ForkJoinPool-1-worker-4]debug16
current thread name = [ForkJoinPool-1-worker-15]debug56
current thread name = [ForkJoinPool-1-worker-8]debug7
current thread name = [ForkJoinPool-1-worker-13]debug43
current thread name = [ForkJoinPool-1-worker-1]debug28
current thread name = [ForkJoinPool-1-worker-9]debug65
current thread name = [ForkJoinPool-1-worker-6]debug81
current thread name = [ForkJoinPool-1-worker-2]debug31
current thread name = [ForkJoinPool-1-worker-10]debug40
current thread name = [ForkJoinPool-1-worker-11]debug90
3-6 收集器
Employee.java
public class Employee {
private String name;
private int age;
private String gender;
private String department;
//工作时间(年)
private int dueTime;
public Employee() {
}
public Employee(String name, int age, String gender, String department, int dueTime) {
this.name = name;
this.age = age;
this.gender = gender;
this.department = department;
this.dueTime = dueTime;
}
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;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public int getDueTime() {
return dueTime;
}
public void setDueTime(int dueTime) {
this.dueTime = dueTime;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", department='" + department + '\'' +
", dueTime=" + dueTime +
'}';
}
}
收集器功能演示
List<Employee> employeeList = new ArrayList<>();
employeeList.add(new Employee("王晓红", 28, "女","前端",10));
employeeList.add(new Employee("韩晨旭", 64, "女","前端",40));
employeeList.add(new Employee("蔡觅风", 33, "女","前端",13));
employeeList.add(new Employee("杨和顺", 33, "男","前端",11));
employeeList.add(new Employee("鱼思博", 26, "男","JAVA开发",5));
employeeList.add(new Employee("孙艺珍", 18, "女","JAVA开发",1));
employeeList.add(new Employee("刘诗诗", 19, "女","JAVA开发",2));
employeeList.add(new Employee("倪妮", 21, "女","JAVA开发",4));
employeeList.add(new Employee("杨幂", 23, "女","JAVA开发",6));
employeeList.add(new Employee("罗玉凤", 45, "女","PHP开发",25));
employeeList.add(new Employee("史恒侠", 52, "女","PHP开发",30));
employeeList.add(new Employee("王诗锦", 36, "女","PHP开发",10));
employeeList.add(new Employee("鲁塞", 36, "男","PHP开发",8));
//获取所有人的工作年限
employeeList.stream()
.map(Employee::getDueTime)
.collect(Collectors.toList())
.forEach(System.out::println);
//分块(男女分块)
Map<Boolean, List<Employee>> collect = employeeList.stream()
.collect(Collectors.partitioningBy(s -> "男".equals(s.getGender())));
System.out.println(collect);
//统计信息(年龄)
IntSummaryStatistics collect1 = employeeList.stream()
.collect(Collectors.summarizingInt(Employee::getAge));
System.out.println(collect1);
//按部门分组
Map<String, List<Employee>> collect2 = employeeList.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
System.out.println(collect2);
//每个部门的人员数
Map<String,Long> departInfo = employeeList.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,Collectors.counting()));
System.out.println(departInfo);
System.out.println("==========每个部门工作年限大于5年的人员==============");
//每个部门工作年限大于5年的人员
Map<String,Long> departInfo2 = employeeList.stream()
.filter(x -> x.getDueTime() >= 5)
.collect(Collectors.groupingBy(Employee::getDepartment,Collectors.counting()));
System.out.println(departInfo2);
3-7 Stream运行机制
public static void main(String[] args) {
Random random = new Random();
Stream.generate(() ->random.nextInt())
//随机产生1000个,无限流需要短路操作
.limit(10)
//第一个无状态操作
.peek( s-> print("peek "+ s))
//第二个无状态操作
.filter(x-> {
print("filter "+ x);
return x > 1000;
})
//终止操作
.count();
}
private static void print(String s) {
System.out.println("Current thread name is [" + Thread.currentThread().getName() +"]" +s);
}
输出结果
Current thread name is [main]peek -1481969448
Current thread name is [main]filter -1481969448
Current thread name is [main]peek 1751174304
Current thread name is [main]filter 1751174304
Current thread name is [main]peek -407154946
Current thread name is [main]filter -407154946
Current thread name is [main]peek -1668783575
Current thread name is [main]filter -1668783575
Current thread name is [main]peek -377677467
Current thread name is [main]filter -377677467
Current thread name is [main]peek 171132531
Current thread name is [main]filter 171132531
Current thread name is [main]peek 440439267
Current thread name is [main]filter 440439267
Current thread name is [main]peek -1525975399
Current thread name is [main]filter -1525975399
Current thread name is [main]peek -598675908
Current thread name is [main]filter -598675908
Current thread name is [main]peek 1409027428
Current thread name is [main]filter 1409027428
所有操作是链式调用,一个元素值迭代一次
每一个中间操作返回一个新的流,流里面有一个属性sourceStage指向同一个地方,就是链表的头Head
Head -> nextStage -> nextStage ···->null
Random random = new Random();
Stream stream = Stream.generate(() ->random.nextInt())
//随机产生1000个,无限流需要短路操作
.limit(10)
//第一个无状态操作
.peek( s-> print("peek "+ s))
//第二个无状态操作
.filter(x-> {
print("filter "+ x);
return x > 1000;
})
//有状态操作
.sorted((x,x2) ->{
print("sorted "+ x + " \t" +x2);
return x.compareTo(x2);
}).peek(s-> print("peek2 "+ s));
//终止操作
stream.count();
输出结果
Current thread name is [main]peek -1219493409
Current thread name is [main]filter -1219493409
Current thread name is [main]peek 129329340
Current thread name is [main]filter 129329340
Current thread name is [main]peek 291924908
Current thread name is [main]filter 291924908
Current thread name is [main]peek -1311720116
Current thread name is [main]filter -1311720116
Current thread name is [main]peek 467565180
Current thread name is [main]filter 467565180
Current thread name is [main]peek -260908389
Current thread name is [main]filter -260908389
Current thread name is [main]peek -866398431
Current thread name is [main]filter -866398431
Current thread name is [main]peek 1719204022
Current thread name is [main]filter 1719204022
Current thread name is [main]peek -964722788
Current thread name is [main]filter -964722788
Current thread name is [main]peek -889925863
Current thread name is [main]filter -889925863
Current thread name is [main]sorted 291924908 129329340
Current thread name is [main]sorted 467565180 291924908
Current thread name is [main]sorted 1719204022 467565180
Current thread name is [main]peek2 129329340
Current thread name is [main]peek2 291924908
Current thread name is [main]peek2 467565180
Current thread name is [main]peek2 1719204022
有状态操作会把无状态操作截断,单独处理。
Random random = new Random();
Stream stream = Stream.generate(() ->random.nextInt())
//随机产生1000个,无限流需要短路操作
.limit(10)
//第一个无状态操作
.peek( s-> print("peek "+ s))
//第二个无状态操作
.filter(x-> {
print("filter "+ x);
return x > 1000;
})
//有状态操作
.sorted((x,x2) ->{
print("sorted "+ x + " \t" +x2);
return x.compareTo(x2);
}).peek(s-> print("peek2 "+ s))
.parallel();
//终止操作
stream.count();
输出结果
Current thread name is [ForkJoinPool.commonPool-worker-4]peek 974711749
Current thread name is [ForkJoinPool.commonPool-worker-4]filter 974711749
Current thread name is [ForkJoinPool.commonPool-worker-4]peek -481309025
Current thread name is [ForkJoinPool.commonPool-worker-4]filter -481309025
Current thread name is [ForkJoinPool.commonPool-worker-4]peek -1304435164
Current thread name is [ForkJoinPool.commonPool-worker-4]filter -1304435164
Current thread name is [ForkJoinPool.commonPool-worker-4]peek 428794899
Current thread name is [ForkJoinPool.commonPool-worker-4]filter 428794899
Current thread name is [ForkJoinPool.commonPool-worker-4]peek 710600140
Current thread name is [ForkJoinPool.commonPool-worker-4]filter 710600140
Current thread name is [ForkJoinPool.commonPool-worker-4]peek 502505696
Current thread name is [ForkJoinPool.commonPool-worker-4]filter 502505696
Current thread name is [ForkJoinPool.commonPool-worker-4]peek 2059903126
Current thread name is [ForkJoinPool.commonPool-worker-4]filter 2059903126
Current thread name is [ForkJoinPool.commonPool-worker-4]peek -751936808
Current thread name is [ForkJoinPool.commonPool-worker-4]filter -751936808
Current thread name is [ForkJoinPool.commonPool-worker-4]peek -142914388
Current thread name is [ForkJoinPool.commonPool-worker-4]filter -142914388
Current thread name is [ForkJoinPool.commonPool-worker-4]peek -1798349696
Current thread name is [ForkJoinPool.commonPool-worker-4]filter -1798349696
Current thread name is [main]sorted 428794899 974711749
Current thread name is [main]sorted 710600140 428794899
Current thread name is [main]sorted 710600140 974711749
Current thread name is [main]sorted 710600140 428794899
Current thread name is [main]sorted 502505696 710600140
Current thread name is [main]sorted 502505696 428794899
Current thread name is [main]sorted 2059903126 710600140
Current thread name is [main]sorted 2059903126 974711749
Current thread name is [main]peek2 710600140
Current thread name is [ForkJoinPool.commonPool-worker-7]peek2 974711749
Current thread name is [ForkJoinPool.commonPool-worker-3]peek2 2059903126
Current thread name is [ForkJoinPool.commonPool-worker-6]peek2 428794899
Current thread name is [ForkJoinPool.commonPool-worker-2]peek2 502505696
并行环境下,有状态的中间值不一定能并行操作
parallel/sequentail是中间操作(返回Stream),但是他们不创建流,值修head的并行标志