概念:
一个高级的迭代器,不是一个数据结构,不是一个结合,不会存放数据。只关注怎么把数据高效的处理。
内部迭代与外部迭代:
public class Test2 {
public static void main(String[] args) {
int[] nums={1,5,6};
//外部迭代 求和
int sum=0;
for (int i :nums) {
sum+=i;
}
System.out.println("结构为:"+sum);
// 使用stream内部迭代 求和
int sum1 = IntStream.of(nums).sum();
System.out.println("结构为:"+sum1);
}
}
外部迭代:自己做逻辑等。内部迭代。只关注结构。代码更加简洁。
中间操作/终止操作和惰性求值:
public class Test2 {
public static void main(String[] args) {
int[] nums={1,5,6};
// 使用stream内部迭代
// map 就是中间操作,(返回stream的操作)
// sum就是终止操作,直接返回结果
IntStream intStream = IntStream.of(nums).map(i -> i * 2);
int sum1 = intStream.sum();
System.out.println("sum1:"+sum1);
//简写
int sum2 = IntStream.of(nums).map(i -> i * 2).sum();
System.out.println("sum2:"+sum2);
//惰性求值 :惰性求值就是终止操作没有调用的情况写,中间操作不做执行
IntStream.of(nums).map(i -> doubleNum(i));
System.out.println("我们可以看到虽然调用了doubleNum()方法,但并没有执行");
}
public static int doubleNum(int i){
System.out.println("执行了乘以2");
return i*2;
}
}
Stream流编程之流的创建
相关方法 | |
集合 | Collection.stream/parallelStream |
数组 | Arrays.stream |
数字Stream | IntStream/LongStream.range/rangeClosed |
Random.ints/longs/doubles | |
自己创建 | Stream.generate/iterate |
public class Test3 {
public static void main(String[] args) {
List<String> list=new ArrayList<>();
//从集合创建
list.stream();
list.parallelStream();
//从数组创建
Arrays.stream(new int[]{2,3,4});
//创建数字流
IntStream.of(1,2,3);
IntStream.rangeClosed(1,10);
IntStream.range(1,10);
//使用random创建一个无限流 后面一般调limit终止,不然会无限下去
Random random = new Random();
random.ints().limit(10);
//自己产生的流 generate("可放任何类型")
Stream.generate(()->random.nextInt()).limit(20);
}
}
Stream流编程之中间操作
相关方法 | |
无状态操作 (当前的操作根其他元素的前后没有依赖关系) | map/mapToXXX |
flatMap/flatMapToXXX | |
filter | |
peek | |
unordered | |
有状态操作 (结果需要依赖元素) | distinct |
sorted | |
limit/skip |
常见的中间操作:
public class Test4 {
public static void main(String[] args) {
String str = "my name is 001";
System.out.println("-------map--------");
//把每个单词的长度打印出来
Stream.of(str.split(" ")).map(s -> s.length()).forEach(s -> System.out.println(s));
System.out.println("-------filter--------");
//通过filter断言,打印长度大于2的单词长度
Stream.of(str.split(" ")).filter(s -> s.length() > 2).map(s -> s.length()).forEach(s -> System.out.println(s));
System.out.println("-------flatMap--------");
//flatMap A->B属性(是个集合),最终得到所有的A元素里面的所有B属性集合
//intStream/longSteam并不是Stream的子类,所以要进行装箱boxed
Stream.of(str.split(" ")).flatMap(s -> s.chars().boxed()).forEach(s -> System.out.println((char) s.intValue()));
System.out.println("--------peek-------");
//peek用于debug,是个中间操作,和forEach是终止操作
Stream.of(str.split(" ")).peek(System.out::println).forEach(System.out::println);
System.out.println("--------limit-------");
//limit使用主要用于限制流
//没加limit的情况下会无限的输出,控制台不结束
//new Random().ints().forEach(System.out::println);
//加入limit(10) 10代表会随机生成10个不定大小的数
// new Random().ints().limit(10).forEach((System.out::println));
//加入limit(10) 随机生成大于1000小于2000的10个数
new Random().ints().filter(i -> i > 1000 && i < 2000).limit(10).forEach((System.out::println));
}
}
Stream流编程之终止操作
相关方法 | |
非短路操作 | forEach/forEachOrdered |
collect/toArray | |
reduce | |
min/max/count | |
短路操作 (不需要所有结果都计算完就可以 结束这个流的操作) | findFirst/findAny |
allMatch/anyMatch/noneMatch |
常见的终止操作
public class Test5 {
public static void main(String[] args) {
String str = "my name is 001";
//使用并行流
str.chars().parallel().forEach(i-> System.out.print((char)i));
System.out.println();
System.out.println("--使用forEach打印,顺序是乱的,使用forEachOrdered打印,顺序是正确的----");
//使用forEachOrdered保证顺序
str.chars().parallel().forEachOrdered(i-> System.out.print((char)i));
/*打印结果
is 010 ya nmem
--使用forEach打印,顺序是乱的,使用forEachOrdered打印,顺序是正确的----
my name is 001
*/
//collect 收集器
List<String> list = Stream.of(str.split(" ")).collect(Collectors.toList());
System.out.println(list);
//使用reduce拼接字符串
Optional<String> letters = Stream.of(str.split(" ")).reduce((s1, s2) -> s1 + "|" + s2);
System.out.println(letters.orElse(""));
//带初始化的reduce 初始为""
String reduce = Stream.of(str.split(" ")).reduce("", (s1, s2) -> s1 + "|" + s2);
System.out.println(reduce);
//计算所有单词的总长度
Integer count = Stream.of(str.split(" ")).map(s -> s.length()).reduce(0, (s1, s2) -> s1 + s2);
System.out.println(count);
//max 的使用
Optional<String> max = Stream.of(str.split(" ")).max((s1, s2) -> s1.length() - s2.length());
System.out.println(max.get());
//使用findFirst短路操作
OptionalInt first = new Random().ints().findFirst();
System.out.println(first.getAsInt());
}
}
4、并行流
public class Test6 {
public static void main(String[] args) {
//调用parallel产生一个并行流
//IntStream.range(1,100).parallel().peek(Test6::debug).count();
//实现先并行再串行
//多次调用 parallel/sequential 以最后一次调用为准
//IntStream.range(1,100)
// //调用parallel产生并行流
// .parallel().peek(Test6::debug)
// //调用sequential产生串行流
// .sequential().peek(Test6::debug2)
// .count();
//并行流使用的线程池:ForkJoinPool.commonPool
//默认线程数是当前机器的cpu个数
//使用这个属性可以修改默认的线程数
// System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism","20");
//IntStream.range(1,100).parallel().peek(Test6::debug).count();
//使用自己的线程池,不适用默认的线程池,防止任务被阻塞
//线程名字:ForkJoinPool-1
ForkJoinPool pool=new ForkJoinPool(20);
pool.submit(()->IntStream.range(1,100).parallel().peek(Test6::debug).count());
pool.shutdown();
synchronized (pool){
try {
pool.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void debug(int i) {
System.out.println(Thread.currentThread().getName() + "debug:" + i);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void debug2(int i) {
System.err.println("debug2:" + i);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
5、收集器:把流处理后的数据收集起来。
public class Test7 {
public static void main(String[] args) {
List<Student> students= Arrays.asList(
new Student("里斯",23,true),
new Student("王二",24,true),
new Student("小明",23,true),
new Student("校长",12,false),
new Student("小王",18,false),
new Student("小白",56,false),
new Student("小黑",11,true));
//得到所有学生的年龄列表,具体生成什么类型根据collect()中的值来定
//尽量使用方法引用,少写lambda表达式:如 s->s.geteAge() -->Student:getAge 不会多生成一个类似lambda$()这样的函数
List<Integer> ages = students.stream().map(Student::getAge).collect(Collectors.toList());
System.out.println("所有学生的年龄:"+ages);
//输出:所有学生的年龄:[23, 24, 23, 12, 18, 56, 11]
//统计汇总信息
IntSummaryStatistics collect = students.stream().collect(Collectors.summarizingInt(Student::getAge));
System.out.println("年龄汇总信息:"+collect);
//输出:年龄汇总信息:IntSummaryStatistics{count=7, sum=167, min=11, average=23.857143, max=56}
//分块:根据一个规则,把数据分成两块
Map<Boolean, List<Student>> genders = students.stream().collect(Collectors.partitioningBy(s ->s.isSex()==true));
System.out.println(genders);
//分组
Map<Boolean, List<Student>> collect1 = students.stream().collect(Collectors.groupingBy(Student::isSex));
System.out.println(collect1);
//得到男女性别的总个数
Map<Boolean, Long> collect2 = students.stream().collect(Collectors.groupingBy(Student::isSex, Collectors.counting()));
System.out.println(collect2);
}
}
class Student{
private String name;
private int age;
//false 男,true 女
private boolean isSex;
public Student() {
}
public Student(String name, int age, boolean isSex) {
this.name = name;
this.age = age;
this.isSex = isSex;
}
public String getName() {
return name;
}
public boolean isSex() {
return isSex;
}
public void setSex(boolean sex) {
isSex = sex;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
stream运行机制:
(1)所有操作都是链式调用,一个元素只迭代一次
(2)每一个中间操作返回一个新的流,流里面有一个属性soureceStage之指向同一个地方,就是Head
(3)有状态操作会把无状态操作阶段单独处理
(4)并行环境下,有状态的中间操作不一定能并行操作
(5)parallel/sequetial这两个操作也是中间操作(也是返回stream)但是他们不创建流,他们只修改Head的并行标准