这里说明一下,Stream流不像传统的java.io中的inputStream和outputStream流,在jdk8中Stream是对集合Connection的增强,Stream比传统的流更加的精炼,语法更加的简洁。
Stream流大大减少对io的频繁操作,并且有着非常不错的性能,连亚马逊对大量数据的分析也是用的Stream流,只需要写少量的代码就能实现功能,非常强大。
使用Stream进行外部迭代
public class StreamDemo1 {
public static void main(String[]args){
//外部迭代
int [] nums = {1,2,3};
int sum = 0;
for (int num : nums) {
sum += num;
}
System.out.println("结果是:" + sum);
//使用Strem进行内部迭代
int sum2 = IntStream.of(nums).map( i -> i *2).sum();
System.out.println("结果为:" + sum2);
System.out.println("惰性求值是终止没有调用的情况下,中间的操作不会执行");
IntStream.of(nums).map(StreamDemo1::doubNum);
}
public static int doubNum(int i){
System.out.println("执行了乘以二");
return i * 2;
}
}
使用Stream流的内部迭代
int sum2 = IntStream.of(nums).map(i -> i*2).num;//使用了Stream的外部迭代
System.out.println("num:" + sum2);
惰性求值
IntStream.of(nums).map(StreamDemo1::doubNum);//这个就是惰性求值
注意:惰性求值是终止没有调用的情况下,中间的操作不会执行
从集合中创建
List<String> list = new ArrayList<String>();
list.stream();
list.parallelStream();//创建并行流
数字流
IntStream.of(1,2,3);
IntStream.rangeClosed(1,10);
从数组总创建
Arrays.Stream(new [] int {1,2,3})
通过随机数创建无线流
new Random.ints().limit(10);
自己产生流
Stream.generate(()-> r.nextInt()).limit(20).forEach(System.out::println);
完整代码
public class StremDemo2 {
public static void main(String[]args){
List<String> list = new ArrayList<>();
//从集合中创建
list.stream();
list.parallelStream();
//从数组中创建
Arrays.stream(new int [] {1,2,3});
//使用rondom创建无线流
new Random().ints().limit(10);
//创建数字流
IntStream.of(1,2,3);
IntStream.rangeClosed(1,10);
Random r = new Random();
//自己产生流
Stream.generate(()-> r.nextInt()).limit(20).forEach(System.out::println);
}
}
完整例子
public class StreamDemo3 {
public static void main(String[]args){
String str = "i want to be a software enginner";
Stream.of(str.split(" ")).map( s -> s.length()).forEach(System.out::println);
Stream.of(str.split(" ")).filter(s -> s.contains("a")).map(s -> s.length()).forEach(System.out::println);
Stream.of(str.split(" ")).flatMap(s -> str.chars().boxed()).forEach(i -> System.out.println((char)i.intValue()));
Stream.of(str.split(" ")).peek(System.out::println).forEach(System.out::println);
//limit 使用 ,主要用于无线流
new Random().ints().filter(i -> i > 100 && i < 1000).limit(10).forEach(System.out::println) ;
}
}
map
Stream.of(str.split(" ")).map( s -> s.length()).forEach(System.out::println);
这句代码的意思将字符串str进行分割 得到完整的单词,然后在将每个单词的长度进行遍历输出
filter
Stream.of(str.split(" ")).filter(s -> s.contains("a")).map(s -> s.length()).forEach(System.out::println);
这句代码的意思将字符串分割后,得到完整的单词并且打印只包含a的单词的长度
flatMap
Stream.of(str.split(" ")).flatMap(s -> str.chars().boxed()).forEach(i -> System.out.println((char)i.intValue()));
这句话的意思是将字符串分割后得到完整的单词并且扁平化进行遍历输出
limit主要用于无线流
new Random().ints().filter(i -> i > 100 && i < 1000).limit(10).forEach(System.out::println) ;
完整例子
public class StreamDemo4 {
public static void main(String[]args){
String str = "hello lambda hello";
//使用并行流
str.chars().parallel().forEach( s -> System.out.println((char)s));
//保证顺序
str.chars().parallel().forEachOrdered(i -> System.out.println((char)i));
//收集器
List<String> list = Stream.of(str.split(" ")).collect(Collectors.toList());
System.out.println("这是一个list:" + list);
//使用reduce拼接字符串
Optional<String> letters = Stream.of(str.split(" ")).reduce((s1,s2) -> s1 + "|" + s2);
System.out.println(letters.orElse(""));
//计算所有单词总长度
Integer lent = Stream.of(str.split(" ")).map(s -> s.length()).reduce(0,(s1,s2) -> s1 + s2);
System.out.println("单词的总长度是:" + lent);
//max
Optional<String> max = Stream.of(str.split(" ")).max((s1,s2) -> s1.length() - s2.length());
System.out.println("单词最长的是:" + max.get());
OptionalInt findFirst = new Random().ints().findFirst();
System.out.println("短路操作" + findFirst.getAsInt());
IntPredicate intPredic = null;
boolean allMath = new Random().ints().allMatch(intPredic);
System.out.println("allmath:" + allMath);
}
需要注意的是下面这中操作是不会保证顺序的
str.chars().parallel().forEach( s -> System.out.println((char)s));
如果想要保证顺序那么使用下面这种方法
str.chars().parallel().forEachOrdered(i -> System.out.println((char)i));
forEachOrdered 会按照顺序进行输出
完整的demo
public class StreamDemo5 {
public static void main(String[]args){
IntStream.range(1,100).parallel().peek(StreamDemo5::debug).count();
//parallel 并行流
IntStream.range(1,100).parallel().peek(StreamDemo5::debug).
//sequential串行流
sequential().peek(StreamDemo5::debug2).count();
ForkJoinPool pool = new ForkJoinPool(20);
pool.submit(() -> IntStream.range(1,100).parallel().peek(StreamDemo5::debug).count());
pool.shutdown();
synchronized (pool){
try {
pool.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//让自己的线层池,不使用默认线程池,防止任务被阻塞
public static void debug(int i){
System.out.println("debug" + i);
System.out.println("线程" + Thread.currentThread().getName() + ":" + i);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void debug2(int i){
System.err.println("debug" + i);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这里需要注意的是,ForkJoinPool是jdk默认提供的线程池,利用这个线程池可以将大任务,拆分成小任务,但是可能会发生线程的阻塞。
public static void debug(int i){
System.out.println("debug" + i);
System.out.println("线程" + Thread.currentThread().getName() + ":" + i);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
我们可以使用自己的线程池,来防止线程被阻塞。
Stream流有很多很有用的方法,比起传统的io流,它显的更加强大,代码更简洁,在配合lambda表达式简直就是如虎添翼。我更希望大家去学习Stream流。