Stream01 定义、迭代、操作、惰性求值、创建流、并行流、收集器、stream运行机制
1 Stream
Stream 是 Java 8 提供的一系列对可迭代元素处理的优化方案,使用 Stream 可以大大减少代码量,提高代码的可读性并且使代码更易并行。
2 迭代
2.1 需求
随机创建int类型的数组,计算数组中各个元素的总和
2.2 思路
2.2.1 外部迭代
通过for循环迭代数组
2.2.2 内部迭代
先将数组转化成流 -> 在通过流的相关操作来实现
2.2.3 外部迭代和内部迭代
外部迭代式串行的,如果要实现并行需要自己编写代码实现;内部迭代实现并行操作只需要调用一个parallel()操作即可以啦
2.3 代码实现
package demo01_iteration; import org.junit.Before;
import org.junit.Test; import java.util.Arrays;
import java.util.Random;
import java.util.stream.IntStream; /**
* @author 王杨帅
* @create 2018-06-24 22:48
* @desc 外部迭代和内部迭代
**/
public class Case01 { private int [] nums;
private int count = 4;
private Random random; @Before
public void init() {
random = new Random();
nums = new int[count];
for (int i = 0; i < nums.length; i++) { // 随机产生数组元素
nums[i] = random.nextInt(30);
}
} /**
* 外部迭代:自己利用for训话实现
*/
@Test
public void test01() {
int sum = 0;
for (int i : nums) {
sum += i;
}
System.out.println(Arrays.toString(nums) + " 各个元素的累加和为:" + sum);
} /**
* 内部迭代:利用流的相关方法实现
*/
@Test
public void test02() {
int sum = 0;
sum = IntStream.of(nums).parallel().sum();
System.out.println(Arrays.toString(nums) + " 各个元素的累加和为:" + sum);
} }
3 操作
3.1 分类
3.1.1 中间操作
返回一个Stream流的操作
package demo05_webflux.chapter03; import java.util.Random;
import java.util.stream.Stream; /**
* @author 王杨帅
* @create 2018-07-30 20:42
* @desc 中间操作
**/
public class Case02StreamDemo02 { public static void main(String [] args) {
String str = "MY NAME IS FURY"; // Stream.of(str.split(" ")).forEach(System.out::println);
//
// Stream.of(str.split(" ")).map(s -> s.length()).forEach(System.out::println); // Stream.of(str.split(" ")) // 获取流
// .map(s -> s.length()) // 获取流元素的长度并将其组成一个流
// .filter(l -> l > 2) // 过滤流
// .forEach(System.out::println); // 循环打印流元素 /**
* flatMap: 一个流由A对象组成,A对象中由B属性,而且属性是一个集合;利用flatMap可以获取到流中所有元素
* 的B属性的元素组合成的新流
*/
// Stream.of(str.split(" "))
// .flatMap(s -> s.chars().boxed())
// .forEach(System.out::println);
// String实例.chars() 返回的结果是 IntStream -> IntStream 不是 Stream 的子类,所以需要用 boxed 做一个装箱擦操作,使之变成 Stream<Integer>
// String str02 = "warrior";
// str02.chars().boxed().forEach(System.out::println); /**
* peek :和forEach的功能是一样的,只不过peek是中间操作【常用于调试】,forEach是终止操作
*/
// Stream.of(str.split(" "))
// .peek(System.out::println)
// .forEach(System.out::println); new Random()
.ints() // 产生流
.filter(i -> i > 10 && i < 100) // 过滤流
.limit(10) // 限制流的长度
.forEach(System.out::println); } }
package demo_test02; import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream; /**
* @author 王杨帅
* @create 2018-08-02 11:04
* @desc
**/
public class Demo03 { public static void main(String[] args) { Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 4, 3, 2, 1, 5); // stream.distinct().forEach(System.out::println); // stream.sorted().forEach(System.out :: println); // stream.limit(5).forEach(System.out :: println); stream.skip(3).forEach(System.out::println); } }
package demo02_operation; import org.junit.Before;
import org.junit.Test; import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Stream; /**
* @author 王杨帅
* @create 2018-06-25 7:46
* @desc 中间操作
**/
public class Case02 { private String str; @Before
public void init() {
str = "My name is warrior and I come from yuzu .";
} /**
* 中间操作:map -> 对每个流元素进行相同操作
*/
@Test
public void test01() { Stream.of(str.split(" ")) // 创建单词流
.map(s -> s.length()) // 中间操作:获取每个单词的长度
// .forEach(System.out::println); // 遍历打印每个单词的长度
.forEach(i -> System.out.println(i)); } /**
* 中间操作:filter -> 主要是过滤作用
*/
@Test
public void test02() {
Stream.of(str.split(" ")) // 创建字符串流
.filter(s -> s.length() >= 4) // 过滤操作:只要单词长度大于等于4的单词
.forEach(System.out::println); // 打印输出:打印单词长度大于等于4的单词
} /**
* 中间操作:flatMap -> A元素中有B元素,而且B元素是一个集合;利用flatMap可以得到B元素集合
* 技巧01:intStream/longStream不是Stream的子类,所以需要进行装箱操作
* 技巧02:Integer类型也不能直接强转成char类型,必须进行拆箱操作
*/
@Test
public void test03() {
// Stream.of(str.split(" "))
// .flatMap(s -> s.chars().boxed())
// .forEach(System.out::println); // 优化之后 Stream.of(str.split(" "))
.flatMap(s -> s.chars().boxed())
.forEach(i -> System.out.println((char)i.intValue()));
} /**
* 中间操作:peek -> 和forEach一行,只不过前者是中间操作用于debug用,后者是终止操作
*/
@Test
public void test04() {
Stream.of(str.split(" "))
.peek(System.out::println)
.forEach(System.out::println);
} /**
* 中间操作:limit -> 主要用于限制无限流
*/
@Test
public void test05() {
new Random().ints()
.filter(i -> i >= 100 && i <= 1000)
.limit(10)
.forEach(System.out::println);
} }
3.1.2 终止操作
返回一个结果的操作
短路操作:发现符合条件的就结束流操作
package demo05_webflux.chapter03; import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream; /**
* @author 王杨帅
* @create 2018-07-30 21:20
* @desc 终止操作
**/
public class Case03StreamDemo03 { public static void main(String[] args) { String str = "my name is fury"; str.chars()
.parallel()
.forEach(i -> System.out.print((char)i)); System.out.println("\n===分割线==="); /**
* forEachOrdered 可以保证顺序
*/
str.chars()
.parallel()
.forEachOrdered(i -> System.out.print((char)i));
System.out.println("\n===分割线==="); // 转化成集合
List<String> list = Stream.of(str.split(" "))
.collect(Collectors.toList());
System.out.println(list);
System.out.println("===分割线==="); // 转化成数组【只能转化成Objec类型的数组】
Object[] arr = Stream.of(str.split(" "))
.toArray();
System.out.println(Arrays.toString(arr));
System.out.println("===分割线==="); /**
* 利用reduce进行拼接【reduce有三个重载方法】
*/
Optional<String> result = Stream.of(str.split(" "))
.reduce((s1, s2) -> s1 + "|" + s2);
System.out.println(result.orElse("数据为空"));
System.out.println("===分割线==="); Integer result02 = Stream.of(str.split(" "))
.map(i -> i.length())
.reduce(0, (s1, s2) -> s1 + s2);
System.out.println(result02);
System.out.println("===分割线==="); Optional<Integer> resul03 = Stream.of(str.split(" "))
.map(s -> s.length())
.max((s1, s2) -> s1 - s2);
System.out.println(resul03.orElse(-1)); } }
package demo02_operation; import org.junit.Before;
import org.junit.Test; import javax.swing.text.html.Option;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream; /**
* @author 王杨帅
* @create 2018-06-25 8:17
* @desc 终止操作
**/
public class Case03 { private String str; @Before
public void init() {
str = "My Name is warrior and I am from yuzu .";
} /**
* 在进行并行操作时 forEachOrdered 的妙用
*/
@Test
public void test01() {
System.out.println("原始数据:" + str);
str.chars() // 将字符串转化成intStream
.parallel() // 并行操作
.forEach(i -> System.out.print((char)i)); // 并行操作时不可以保证顺序
System.out.println();
System.out.println("===分割线===");
str.chars()
.parallel()
.forEachOrdered(i -> System.out.print((char)i)); // 并行操作时可以保证顺序
} /**
* 终止操作:collect -> 将流转化成一个集合
*/
@Test
public void test02() {
List<String> stringList = Stream.of(str.split(" ")) // 创建单词流
.collect(Collectors.toList()); // 将单词流转化成集合 System.out.println(stringList);
} /**
* 终止操作: toArray -> 将流转化成一个数组
*/
@Test
public void test03() {
Object[] objects = Stream.of(str.split(" "))
.toArray(); System.out.println(Arrays.toString(objects));
} /**
* 终止操作:reduce -> 拼接流元素
*/
@Test
public void test04() { Optional<String> optional = Stream.of(str.split(" "))
.reduce((s1, s2) -> s1 + "|" + s2); // System.out.println(optional.get()); // 如果为空会抛出异常
System.out.println(optional.orElse("数据为空")); // 如果为空就返回提示信息【推荐使用】 } /**
* 终止操作:reduce 之 带初始化的reduce终止操作
*/
@Test
public void test05() {
String result = Stream.of(str.split(" "))
.reduce("", (s1, s2) -> s1 + "|" + s2); System.out.println(result);
} /**
* 终止操作:reduce 之 带初始化的reduce终止操作小demo
*/
@Test
public void test06() {
Integer integer = Stream.of(str.split(" "))
.map(s -> s.length())
.reduce(0, (s1, s2) -> s1 + s2); System.out.println("所有流单词的长度为:" + integer);
} /**
* 终止操作:max -> 获取最大值
*/
@Test
public void test07() {
System.out.println("原始数据:" + str); Optional<String> optional = Stream.of(str.split(" "))
.max((s1, s2) -> s1.length() - s2.length()); System.out.println(optional.get());
} /**
* 终止操作: min -> 获取最小值
*/
@Test
public void test08() {
System.out.println("原始数据:" + str); Optional<String> optional = Stream.of(str.split(" "))
.min((s1, s2) -> s1.length() - s2.length()); System.out.println(optional.get());
} /**
* 终止操作:count -> 获取流中的元素数量
*/
@Test
public void test09() {
System.out.println("原始数据为:" + str);
Long num = Stream.of(str.split(" "))
.count();
System.out.println("流中元素的数量为:" + num);
} /**
* 终止操作:findFirst -> 寻找流中的第一个元素
*/
@Test
public void test11() {
OptionalInt first = new Random().ints().findFirst();
System.out.println("流中的第一个元素为:" + first);
} /**
* 中间操作:sorted -> 排序操作
*/
@Test
public void test10() {
List<String> result = Stream.of(str.split(" ")) // 获取单词流
.sorted(Comparator.comparing(i -> i.length())) // 根据长度排序
.collect(Collectors.toList()); System.out.println(result);
} }
3.2 代码体验
package demo02_operation; import org.junit.Before;
import org.junit.Test; import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Random;
import java.util.stream.IntStream; /**
* @author 王杨帅
* @create 2018-06-24 23:04
* @desc 中间操作、终止操作、惰性求值
**/
public class Case01 { private int [] nums;
private int count = 5;
private Random random; @Before
public void init() {
random = new Random();
nums = new int[count];
for (int i = 0; i < nums.length; i++) {
nums[i] = random.nextInt(30);
}
} /**
* 终止操作: 返回一个结果的操作
*/
@Test
public void test01() {
int sum = IntStream.of(nums).sum();
System.out.println(Arrays.toString(nums) + " 各个元素之和为: " + sum);
} /**
* 中间操作:返回一个流的操作【例如:Map操作】
*/
@Test
public void test02() {
System.out.println("老的数组为:" + Arrays.toString(nums));
int [] newNums = IntStream.of(nums).map(s -> s + 2).toArray();
System.out.println("新的数组为:" + Arrays.toString(newNums));
} }
4 惰性求值
如果流的操作中没有执行终止操作也不会执行中间操作
4.1 代码体验
package demo02_operation; import org.junit.Before;
import org.junit.Test; import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Random;
import java.util.stream.IntStream; /**
* @author 王杨帅
* @create 2018-06-24 23:04
* @desc 中间操作、终止操作、惰性求值
**/
public class Case01 { private int [] nums;
private int count = 5;
private Random random; @Before
public void init() {
random = new Random();
nums = new int[count];
for (int i = 0; i < nums.length; i++) {
nums[i] = random.nextInt(30);
}
} /**
* 惰性求值
*/
@Test
public void test01() {
System.out.println("老的数组为:" + Arrays.toString(nums));
// IntStream.of(nums).map(Case01::addFive); // 没有终止操作,map操作不会执行
IntStream.of(nums).map(Case01::addFive).sum(); // 有中间操作,map操作会执行
} public static Integer addFive(Integer num) {
System.out.println("中间操作执行了");
return num + 5;
} }
5 创建流
5.1 创建流的方式
5.2 代码体验
package demo03_create_stream; import org.junit.Test; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream; /**
* @author 王杨帅
* @create 2018-06-25 6:57
* @desc 创建流的方法
**/
public class Case01 { /**
* 根据集合创建流
*/
@Test
public void test01() {
List<Integer> integerList = new ArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(3); /**
* 根据集合创建流的两种方式
*/
integerList.stream();
integerList.parallelStream();
} /**
* 根据数组创建流
*/
@Test
public void test02() {
int [] nums = {1,2,3,4}; Arrays.stream(nums);
} /**
* 创建数字流
*/
@Test
public void test03() {
IntStream.of(1, 2, 3); int [] nums = {4, 5, 6};
IntStream.of(nums); IntStream.range(1, 10); IntStream.rangeClosed(1, 10);
} /**
* 利用Random实例创建无限流
* limit的作用是限制个数,避免创建无限流
*/
@Test
public void test04() {
new Random().ints().limit(10);
} /**
* 自己产生流
*/
@Test
public void test05() {
Random random = new Random();
Stream.generate(() -> random.nextInt()).limit(20);
} }
6 并行流
就是并行的操作流
package demo05_webflux.chapter03; import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream; /**
* @author 王杨帅
* @create 2018-07-31 9:48
* @desc 并行操作
**/
public class Case04StreamDemo04 { public static void main(String[] args) { // 01 串行操作
// IntStream.range(1, 100)
// .peek(Case04StreamDemo04 :: debug)
// .count(); // 02 并行操作
// IntStream.range(1, 100)
// .parallel()
// .peek(Case04StreamDemo04 :: debug)
// .count(); // 03 先并行再串行
/**
* 结论:多次调用串行和并行后,以最后一次为准
*/
// IntStream.range(1, 100)
// .parallel()
// .peek(Case04StreamDemo04 :: debug)
// .sequential()
// .peek(Case04StreamDemo04 :: debug02)
// .count(); // IntStream.range(1, 100)
// .sequential()
// .peek(Case04StreamDemo04 :: debug)
// .parallel()
// .peek(Case04StreamDemo04 :: debug02)
// .count(); // 04 并行操作时打印线程信息
/**
* 结论:
* 并行流使用的线程池是 ForkJoinPool.commonPool【JDK自带的】;
* 默认的线程数时物理机器中cpu个的数量
* 可以通过java.util.concurrent.ForkJoinPool.common.parallelism属性
* 来修改默认的线程数
*
*
*/
// System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");
// IntStream.range(1, 100)
// .parallel()
// .peek(Case04StreamDemo04::debug03)
// .count(); // 05 使用自己的线程池进行并行操作
/**
* note:
* 1 不使用默认的线程池,是为了防止阻塞
* 2 线程池名字是:ForkJoinPool-1
*/
ForkJoinPool pool = new ForkJoinPool(20);
pool.submit(() -> IntStream.range(1, 100)
.parallel()
.peek(Case04StreamDemo04 :: debug03)
.count()
);
pool.shutdown(); // 关闭线程池 synchronized (pool) {
try {
pool.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} } public static void debug(Integer i) { System.out.println("Debug" + i); try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} } public static void debug02(Integer i) { System.err.println("Debug" + i); try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} } public static void debug03(Integer i) {
System.out.println(Thread.currentThread().getName() + "-Debug-" + i);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
package demo04_parallel_stream; import demo02_operation.Case02;
import org.junit.Test; import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream; /**
* @author 王杨帅
* @create 2018-06-25 21:59
* @desc
**/
public class Case01 { /**
* 串行操作流
*/
@Test
public void test01() {
IntStream.range(1, 100).peek(Case01::debug).count();
} /**
* 并行操作流
* 技巧01:并行的数量默认是物理即CPU的数量
*/
@Test
public void test02() {
IntStream.range(1, 100).parallel().peek(Case01::debug).count();
} /**
* 多次调用parallel和sequential,以最后一次为准
*/
@Test
public void test03() {
IntStream.range(1, 100)
.parallel().peek(Case01::debug)
.sequential().peek(Case01::debug2)
.count();
} /**
* 并行流默认的线程池:ForkJoinPool.commonPool
* 技巧01:线程池默认的线程数量是物理机器的cpu个数
*/
@Test
public void test04() {
IntStream.range(1, 100)
.parallel().peek(Case01::debug3)
.count();
} /**
* 修改默认的线程数量
*/
@Test
public void test05() {
// 修改并行操作时系统默认的线程数量
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20"); IntStream.range(1, 100)
.parallel().peek(Case01::debug)
.count();
} /**
* 使用自己的线程池进行并行操作,不使用默认的线程池;目的是为了防止任务被阻塞
* 技巧01:自己创建的线程池使用的是 ForkJoinPool
*/
@Test
public void test06() {
// 创建一个拥有10个线程的线程池
ForkJoinPool forkJoinPool = new ForkJoinPool(10); // 将并行操作放到线程池中
forkJoinPool.submit(() -> IntStream.range(1, 100)
.parallel().peek(Case01::debug3)
.count());
// 并行操作完成后关闭线程池
forkJoinPool.shutdown(); // 让主线程等待一下
synchronized (forkJoinPool) {
try {
forkJoinPool.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} } public static void debug(int i) {
System.out.println("debug " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
} public static void debug2(int i) {
System.err.println("debug2 " + i);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
} public static void debug3(int i) {
System.out.println(Thread.currentThread().getName() + " debug3 " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
7 收集器
7.1 准备
package demo05_webflux.chapter03; /**
* @author 王杨帅
* @create 2018-08-01 9:42
* @desc 学生实体类
**/
public class Student {
private String name;
private Integer age;
private Gender gender;
private Grade grade; public Student(String name, Integer age, Gender gender, Grade grade) {
this.name = name;
this.age = age;
this.gender = gender;
this.grade = grade;
} 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 Gender getGender() {
return gender;
} public void setGender(Gender gender) {
this.gender = gender;
} public Grade getGrade() {
return grade;
} public void setGrade(Grade grade) {
this.grade = grade;
} @Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
", grade=" + grade +
'}';
}
}
Student.java
package demo05_webflux.chapter03; /**
* @author 王杨帅
* @create 2018-08-01 9:44
* @desc 性别枚举
**/
public enum Gender {
MALE,
FEMALE;
}
Gender.java
package demo05_webflux.chapter03; /**
* @author 王杨帅
* @create 2018-08-01 9:45
* @desc 班级枚举
**/
public enum Grade {
ONE,
TWO,
THREE,
FOUR,
FIVE;
}
Grade.java
package demo05_webflux.chapter03; import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; /**
* @author 王杨帅
* @create 2018-08-01 9:41
* @desc 搜集器
**/
public class Case05StreamDemo05 { public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student("fury", 1, Gender.MALE, Grade.ONE),
new Student("fury01", 2, Gender.MALE, Grade.THREE),
new Student("fury02", 3, Gender.FEMALE, Grade.ONE),
new Student("fury03", 4, Gender.MALE, Grade.FOUR),
new Student("fury04", 5, Gender.FEMALE, Grade.ONE),
new Student("fury05", 6, Gender.MALE, Grade.ONE),
new Student("fury06", 7, Gender.FEMALE, Grade.TWO),
new Student("fury07", 8, Gender.MALE, Grade.ONE),
new Student("fury08", 9, Gender.FEMALE, Grade.THREE),
new Student("fury09", 10, Gender.MALE, Grade.ONE)
); /**
* Notes:
* 1 多使用方法引用来代替lambda表达式,这样可以少生成一个lambda$0这样的函数
*/
List<Integer> ageList = students.stream()
.map(Student :: getAge)
.collect(Collectors.toList());
System.out.println("所有学生的年龄为:" + ageList); // 02 信息汇总、
IntSummaryStatistics agesSummaryStatistics =
students.stream().collect(Collectors.summarizingInt(Student :: getAge));
System.out.println(agesSummaryStatistics); // 03 分块【就是一个只有两个组的特殊分组】
Map<Boolean, List<Student>> genderCollect = students.stream().collect(Collectors.partitioningBy(s -> s.getGender() == Gender.MALE));
System.out.println("男女学生分别为:" + genderCollect); // 04 分组
Map<Grade, List<Student>> gradeGroup = students.stream()
.collect(Collectors.groupingBy(Student::getGrade));
System.out.println("班级分组为:" + gradeGroup); Map<Grade, Long> collect = students.stream()
.collect(Collectors.groupingBy(Student::getGrade, Collectors.counting()));
System.out.println("各个班级的学生个数为:" + collect); } }
package demo05_collector; import com.sun.org.apache.xpath.internal.operations.Bool;
import org.apache.commons.collections4.MapUtils;
import org.junit.Before;
import org.junit.Test; import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.Collectors; /**
* @author 王杨帅
* @create 2018-06-25 22:51
* @desc
**/
public class Case01 { private List<Student> students; @Before
public void init() {
students = Arrays.asList(
new Student("fury", 1, Gender.MALE, Grage.ONE),
new Student("fury01", 2, Gender.MALE, Grage.THREE),
new Student("fury02", 3, Gender.FEMALE, Grage.ONE),
new Student("fury03", 4, Gender.MALE, Grage.FOUR),
new Student("fury04", 5, Gender.FEMALE, Grage.ONE),
new Student("fury05", 6, Gender.MALE, Grage.ONE),
new Student("fury06", 7, Gender.FEMALE, Grage.TWO),
new Student("fury07", 8, Gender.MALE, Grage.ONE),
new Student("fury08", 9, Gender.FEMALE, Grage.THREE),
new Student("fury09", 10, Gender.MALE, Grage.ONE)
);
} /**
* 所有学生的年龄列表
* 技巧:lambda表达式能用引用就尽量用引用,少用箭头函数;这样就不会多生成一个类似lambda$0这样的函数【参见lambda底层】
*/
@Test
public void test01() {
// System.out.println(students);
List<Integer> ageList = students.stream()
.map(Student::getAge)
// .collect(Collectors.toList());
.collect(Collectors.toCollection(ArrayList::new)); System.out.println("所有学生的年龄集合为:" + ageList);
} /**
* 统计
*/
@Test
public void test02() {
IntSummaryStatistics summaryStatistics = students.stream().collect(Collectors.summarizingInt(Student::getAge)); System.out.println("年龄汇总信息:" + summaryStatistics);
} /**
* 分块
*/
@Test
public void test03() {
Map<Boolean, List<Student>> map = students.stream().collect(Collectors.partitioningBy(s -> s.getGender() == Gender.MALE)); MapUtils.verbosePrint(System.out, "男女学生列表为:", map);
} /**
* 分组
*/
@Test
public void test04() {
Map<Grage, List<Student>> map = students.stream().collect(Collectors.groupingBy(Student::getGrage)); MapUtils.verbosePrint(System.out, "学生班级列表为:", map);
} /**
* 分组下级操作
*/
@Test
public void test05() {
Map<Grage, Long> map = students.stream().collect(Collectors.groupingBy(Student::getGrage, Collectors.counting())); MapUtils.verbosePrint(System.out, "班级学生数量列表为:", map);
} }
8 stream运行机制
package demo06_stream_run; import org.junit.Test; import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream; /**
* @author 王杨帅
* @create 2018-06-26 6:38
* @desc
**/
public class Case01 { /**
* Notes:
* 1 所有操作都是链式操作,一个元素只迭代一次
* 2 每一个中间操作都返回一个新的流
* 流里面有一个属性叫sourceStage,它都指向同一个地方就是这个流的Head
* Head -> nextStage -> nextStage -> ... -> null
*/
@Test
public void test01() {
Random random = new Random();
Stream<Integer> stream = Stream.generate(() -> random.nextInt()) // 产生流
// 短路操作
.limit(500)
// 中间操作(无状态)
.peek(s -> System.out.println("peek: " + s))
// 中间操作(无状态)
.filter(s -> {
System.out.println("filter: " + s);
return s > 1000000;
}); // 终止操作
stream.count();
} /**
* Notes:
* 3 有状态操作会将无状态操作截断,单独处理
*/
@Test
public void test02() {
Random random = new Random();
Stream<Integer> stream = Stream.generate(() -> random.nextInt()) // 产生流
// 短路操作
.limit(500)
// 中间操作(无状态)
.peek(s -> System.out.println("peek: " + s))
// 中间操作(无状态)
.filter(s -> {
System.out.println("filter: " + s);
return s > 1000000;
})
// 中间操作(有状态)
.sorted((i1, i2) -> {
System.out.println("排序:" + i1 + "," + i2);
return i1.compareTo(i2);
})
// 中间操作(无状态)
.peek(s -> System.out.println("peek2: " + s)); // 终止操作
stream.count();
} /**
* Notes:
* 4 并行环境下,有状态的并行操作不一定能并行操作
* 5 parallel和sequetial者两个操作也是中间操作(也是返回流)
* 注意:他们不创建流,他们只修改Head的并行标志
*/
@Test
public void test03() {
Random random = new Random();
Stream<Integer> stream = Stream.generate(() -> random.nextInt()) // 产生流
// 短路操作
.limit(500)
// 中间操作(无状态)
.peek(s -> print("peek: " + s))
// 中间操作(无状态)
.filter(s -> {
print("filter: " + s);
return s > 1000000;
})
// 中间操作(有状态) 【并行环境下时不能进行并行操作】
.sorted((i1, i2) -> {
print("排序:" + i1 + "," + i2);
return i1.compareTo(i2);
})
// 中间操作(无状态)
.peek(s -> print("peek2: " + s))
.parallel(); // 终止操作
stream.count();
} public void print(String s) {
System.out.println(Thread.currentThread().getName() + " -> " + s);
// try {
// TimeUnit.SECONDS.sleep(1);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
} }
8.1 链式调用
所有的操作都是链式调用,每个操作只会对每个元素操作一次;
每个中间操作都会返回一个新的流,每个流里面都会有一个SourceStage属性,所有流的SourceStage属性都指向同一个地方【就是原始流的头部】;
如果一个中间操作之后还有中间操作,那么这个中间操作对应的流中nextStage属性就会执行下一个中间操作对应的流,否则就是null
技巧01:返回一个流的操作都叫作中间操作【原始流也看作是一个中间操作??】
package demo05_webflux.chapter03; import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream; /**
* @author 王杨帅
* @create 2018-08-01 10:58
* @desc Stream的运行机制
**/
public class Case06StreamDemo06 { public static void main(String[] args) { Stream<Integer> integerStream = Stream.generate(() -> new Random().nextInt())
.limit(500)
.peek(s -> System.out.println("peek:" + s))
.filter(s1 -> {
System.out.println("filter:" + s1);
return s1 > 100;
}); integerStream.count();
} }
8.2 有状态操作对无状态操作的影响
技巧01:如果所有操作都是无状态操作,那么都是链式调用的;但是如果在无状态操作之间添加了有状态操作,那么有状态操作会将链式操作截成两部分,那两部分分别进行链式操作
例如:无状态操作A -> 无状态操作B -> 无状态操作C -> 无状态操作D
这种情况下所有的操作都是链式的
例如:无状态操作A -> 无状态操作B -> 无状态操作Y -> -> 无状态操作C -> 无状态操作D
Y会将之前的链式操作截成两个链式操作,Y之前的A、B操作是基于原始流进行链式操作,Y之后的C、D操作是基于Y产生的流进行的链式操作
package demo05_webflux.chapter03; import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream; /**
* @author 王杨帅
* @create 2018-08-01 10:58
* @desc Stream的运行机制
**/
public class Case06StreamDemo06 { public static void main(String[] args) { Stream<Integer> integerStream = Stream.generate(() -> new Random().nextInt())
.limit(10)
.peek(s -> System.out.println("peek:" + s))
.filter(s1 -> {
System.out.println("filter:" + s1);
return s1 == s1;
})
.sorted((s1, s2) -> {
System.out.println("排序:" + s1 + "," + s2);
return s1.compareTo(s2);
})
.peek(s -> System.out.println("peek02-:" + s))
; integerStream.count();
} }
8.3 并行操作对有状态的中间操作的影响
有状态的中间操作并不一定可以进行并行操作
package demo05_webflux.chapter03; import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream; /**
* @author 王杨帅
* @create 2018-08-01 10:58
* @desc Stream的运行机制
**/
public class Case06StreamDemo06 { public static void main(String[] args) { Stream<Integer> integerStream = Stream.generate(() -> new Random().nextInt())
.limit(500)
.peek(s -> print("peek:" + s))
.filter(s1 -> {
print("filter:" + s1);
return s1 == s1;
})
.sorted((s1, s2) -> {
print("排序:" + s1 + "," + s2);
return s1.compareTo(s2);
})
.peek(s -> print("peek02-:" + s))
.parallel()
; integerStream.count();
} public static void print(String s) {
System.out.println(Thread.currentThread().getName() + "-" + s);
} }
8.4 特殊的中间操作
parallel和sequetial这两个操作也是中间操作(返回的也是stream);
但是他们不创建流,只是改变流中 sourceStage 中的 parallel 属性而已(并行时为true,串行时为false【默认为false】)
9 stream小结
Stream01 定义、迭代、操作、惰性求值、创建流、并行流、收集器、stream运行机制的更多相关文章
- C#函数式编程之惰性求值
惰性求值 在开始介绍今天要讲的知识之前,我们想要理解严格求值策略和非严格求值策略之间的区别,这样我们才能够深有体会的明白为什么需要利用这个技术.首先需要说明的是C#语言小部分采用了非严格求值策略,大部 ...
- c++11实现l延迟调用(惰性求值)
惰性求值 惰性求值一般用于函数式编程语言中,在使用延迟求值的时候,表达式不在它被绑定到变量之后就立即求值,而是在后面的某个时候求值. 可以利用c++11中的std::function, lam ...
- 惰性求值——lodash源码解读
前言 lodash受欢迎的一个原因,是其优异的计算性能.而其性能能有这么突出的表现,很大部分就来源于其使用的算法--惰性求值. 本文将讲述lodash源码中,惰性求值的原理和实现. 一.惰性求值的原理 ...
- GString惰性求值
当对一个GString实例求值时,如果其中包含一个变量,该变量的值会被简单地打印到一个Writer,通常是一个StringWriter.然而,如果GString中包含的是一个闭包,而非变量,该闭包就会 ...
- python 惰性求值 https://blog.csdn.net/Appleyk/article/details/77334221
为什么调用的不是同一个函数呢 是因为调用函数后,函数的生命周期就结束了,再调用就是另一个函数了
- 《EOPL》: 实现了惰性求值的两种参数传递策略
call-by-need 不过是比 call-by-name 多了一个 memorization 的步骤
- [SICP] 求值规则
在Java语言学习中,通常不太关注求值规则. (2+4*6)*(3+5+7)这样的组合式的求值规则.通常归结为优先级问题: if.for等的求值规则通常归结为语义. 函数式编程语言的Scheme,将这 ...
- 洛谷P7112 行列式求值
行列式求值 这是一个让你掉头发的模板题 行列式的定义 行列式 (\(\texttt{Determinant}\)) 是一个函数定义,取值是一个标量. 对一个 \(n\times n\) 的矩阵 \(A ...
- 创建数据收集器集(DSC)
TechNet 库 Windows Server Windows Server 2008 R2 und Windows Server 2008 按类别提供的 Windows Server 内容 按类别 ...
随机推荐
- 【数据库】SQLite学习
http://www.cnblogs.com/fnng/archive/2013/05/26/3099547.html
- SSH项目配置数据源的方法(jndi)
1.在tomcat6.0/conf/context.xml加入以下代码 [xhtml] view plain copy <Resource name="jdbc/oracleD ...
- C#网络编程(异步传输字符串) - Part.3
这篇文章我们将前进一大步,使用异步的方式来对服务端编程,以使它成为一个真正意义上的服务器:可以为多个客户端的多次请求服务.但是开始之前,我们需要解决上一节中遗留的一个问题. 消息发送时的问题 这个问题 ...
- Ubuntu的复制粘贴操作及常用快捷键(摘自网络)
Ubuntu的复制粘贴操作 终端最大化快捷键:crtl + win + 上 1.最为简单,最为常用的应该是鼠标右键操作了,可以选中文件,字符等,右键鼠标,复制,到目的地右键鼠标,粘贴就结束了. 2.快 ...
- (转)Android和JavaScript互相调用
Html页面和Java代码结合的方式一般用在界面经常被更改 的情况下,可以讲html放在网络中,软件一打开就会访问网络获取到最新的界面.缺点是会受到网络信号的影响,从而导致访问速度慢. 1.用WebV ...
- bootstrap 设置表格固定宽度 内容换行
在项目中开发的时候用的bootstrap,但是有些表格的内容 会显示的很长 那么我第一时间想到的就是 修改td或者th的width,但是我设置了 之后不起作用 于是百度找到了解决方法: 学习源头: h ...
- java代码初学者适用,输入学生成绩,符合要求的过~~~~注意数据范围
总结:没有基础,我从点滴开始, package com.aaa; import java.util.Scanner; //输入“repate ”次数,输入学生成绩,低于60分,输出fail.否则输入p ...
- 启用不安全的HTTP方法解决方案
启用不安全的HTTP方法解决方案 Web AppScan HTTP WebDAV 近期通过APPScan扫描程序,发现了不少安全问题,通过大量查阅和尝试最终还是解决掉了,于是整理了一下方便查阅. 1. ...
- 第15届浙江省赛 E LIS
LIS Time Limit: 1 Second Memory Limit: 65536 KB Special Judge DreamGrid is learning the LI ...
- 1017 Queueing at Bank
题意:银行有K个窗口用于服务,给出所有人的达到时间T和服务时间P,计算所有被服务的客户的平均等待时间.任何客户的服务时间不得超过60分钟.早于08:00到的,要等到08:00:在17:00:01及之后 ...