Java 8之Stream入门

Stream

Java8新特性增加了一个新的抽象称为流Stream。目的在于弥补Java函数式编程的缺陷。将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。

简单来说,Stream 就如同一个迭代器(Iterator),单向且数据只能遍历一次。

流的用法

在使用一个流时,一般是:获取一个数据源(source)-> 数据转换 -> 执行操作获取想要的结果。

其中数据转换每次都返回一个新的Stream,这样多个操作就构成了一个管道。最后从管道中获取我们的结果。

流的创建

实际使用时,有多种方式生成Stream。

方式方法例子
Collection 和ArraysCollection.stream()
Collection.parallelStream()
Arrays.stream(ary)
Stream<String> stream = strs.stream();
Stream<String> streams = strs.parallelStream();
Stream<String> stream = Arrays.stream(new String[]{"First", "Second"});
BufferedReaderjava.io.BufferedReader.lines()BufferedReader br = new BufferedReader(new FileReader("text.txt"));
Stream<String> stream = br.lines();
静态工厂java.util.stream.IntStream.range()
java.nio.file.Files.walk()
 
自己构建java.util.Spliterator 
其它Random.ints()
BitSet.stream()
Pattern.splitAsStream(java.lang.CharSequence)
JarFile.stream()
 


流的操作类型

流的操作类型有两种:

Intermediate:一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。

Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。


流的使用

基本类型

对于基本数值型,目前有三种对应的包装类型 Stream:IntStream、LongStream、DoubleStream。当然我们也可以用 Stream<Integer>、Stream<Long> >、Stream<Double>,我们知道Java中 拆箱和装箱的操作会很耗时,所以特别为这三种基本数值型提供了对应的 Stream。

操作

上边说了操作分两类,下边分两类说明:

操作类型函数作用
Intermediatemap映射成 output Stream 的另外一个元素
 flatMap是一对多映射关系的,这时需要 flatMap
 mapToInt 
 filter 
 distinct 
 sorted 
 peek对每个元素执行操作并返回一个新的 Stream
 limit返回 Stream 的前面 n 个元素
 skip扔掉前 n 个元素
 parallel 
 sequential 
 unordered 
TerminalforEachforEach 方法接收一个 Lambda 表达式,然后在 Stream 的每一个元素上执行该表达式
 forEachOrdered 
 toArray 
 reduce给一个起始值,把 Stream 元素组合起来,
 collect 
 min 
 max 
 count 
 anyMatch 
 allMatch 
 noneMatch 
 findFirst 
 findAny 
 iterator 

lambda表达式

Java 8终于引进了lambda表达式,java离函数式编程更近一步。学过ES6 的该知道,lambda表达式又叫箭头函数。

在Java8之前,一般排序时代码如下:

        List<String> strs = new ArrayList<String>();
        Collections.sort(strs, new Comparator<String>() {
            public int compare(String str1, String str2) {
                return str1.compareToIgnoreCase(str2);
            }
        });

我们知道,实际上这里生成了一个匿名内部类。而在Java8中,可以写成如下:

        Collections.sort(strs, (str1, str2) -> {
            return str1.compareToIgnoreCase(str2);
        });
符号 ()->{} 表示lambda函数。然后根据返回类型,自动推导出函数返回类型。

那么Lambda表达式是怎么实现的呢?下边是一个新建的类。

public class TryLambda {
    public static void  main(String[] args) {
    	List<String> strs = new ArrayList<>();
    	strs.add("kaka");
    	strs.add("hust");
    	Collections.sort(strs, (str1, str2)-> {
            return str1.compareTo(str2);
        });
	}
}

然后对其进行编译:

javac TryLambda.java

此时生成 TryLambda.class 文件。然后利用JDK自带工具,对该文件进行反编译:

javap -p TryLambda.class

发现输出如下:

Compiled from "TryLambda.java"
public class com.lambda.TryLambda {
  public com.lambda.TryLambda();
  public static void main(java.lang.String[]);
  private static int lambda$main$0(java.lang.String, java.lang.String);
}
我们知道,从上边的结果中发,它根据lambda表达式生成了一个静态的私有函数。

好了,继续执行以下命令查看下它的字节码指令:

javap -c -p TryLambda.class

结果如下:

Compiled from "TryLambda.java"
public class com.lambda.TryLambda {
  public com.lambda.TryLambda();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/util/ArrayList
       3: dup
       4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
       7: astore_1
       8: aload_1
       9: ldc           #4                  // String kaka
      11: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      16: pop
      17: aload_1
      18: ldc           #6                  // String hust
      20: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      25: pop
      26: aload_1
      27: invokedynamic #7,  0              // InvokeDynamic #0:compare:()Ljava/util/Comparator;
      32: invokestatic  #8                  // Method java/util/Collections.sort:(Ljava/util/List;Ljava/util/Comparator;)V
      35: return

  private static int lambda$main$0(java.lang.String, java.lang.String);
    Code:
       0: aload_0
       1: aload_1
       2: invokevirtual #9                  // Method java/lang/String.compareTo:(Ljava/lang/String;)I
       5: ireturn
}

待续


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值