jdk1.8特性——lambda表达式、stream学习,结合使用

       最近再项目中用到了lambda和Stream,发现用起来代码很简洁,就是有些复杂点的可能用完后可读性不是很理想,但是简单点的还是很好理解的,因此专门试了试,感觉真的很棒~先来了解一下

一:lambda表达式

        lambda语法:

    1.多参数

     1. lambda表达式的基本格式为(x1,x2)->{表达式...};

     2. 在上式中,lambda表达式带有两个参数,此时参数类型可以省略,但两边的括号不能省略

     3. 如果表达式只有一行,那么表达式两边的花括号可以省略

public static  void test1_() {
    List usersList = new ArrayList() {
        {
            add(new User("user1", "stu1", 10));
            add(new User("user2", "stu2", 6));
            add(new User("user3", "stu3", 8));
            add(new User("user4", "stu4", 7));
        }
    };
    Collections.sort(usersList, (s1, s2) -> Integer.compare(s1.getAge(), s2.getAge()));
    System.out.println(usersList);
}

    2.对于没有参数的情况

      1.参数的括号不能省略,

      2.其他语法同多参数

如:无lambda

public static void testThread(){
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("hello, testThread !");
        }
    }).start();
}

如:通过lambda写法

public static void testThreadLambda(){
    new Thread(()-> System.out.println("hello, testThreadLambda!")).start();
}

一:stream()

  1. Stream是元素的集合,这点让Stream看起来用些类似Iterator
  2. 可以支持顺序和并行的对原Stream进行汇聚的操作;

        可以认为Stream是一个高级版本的iterator,原始版本的iterator,用户只能一个一个的遍历元素并对其执行某些操作,而stream,只要给出需要对其包含的元素执行什么操作,比如“获取每个字符串的首字母”,“将每个字符串的字母改为大写”等,具体的这些操作如何应用到每个元素上,交给stream就好了。

List nums = new ArrayList(){
     {
         add(1);
         add(null);
         add(2);
         add(3);
         add(null);
     }
 };
Long numCount = nums.stream().filter(num -> num != null).count();
System.out.println("numCount="+numCount);

 借用别人的图来分析一下~哈哈

                      jdk1.8特性——lambda表达式、stream学习,结合使用_第1张图片

        可以看到红色区域是Strean的生命开始的地方,负责创建一个Stream实例;绿色框中的语句是赋予Stream灵魂的地方,把一个Stream转换成另一个Stream,红框中的语句生成的是包含所有nums变量的Stream,经过绿框的filter以后,重新生成了一个过滤掉原nums列表所有null以后的Stream, 蓝色框中的语句是把Stream的里面包含的内容按照某种算法来汇聚成一个值,例子中是获取Stream中包含的元素个数。

总结一下使用Stream的基本步骤:

  1. 创建Stream。
  2. 转换Stream,每次转换原有Stream对象不改变,返回的是一个新的Stream对象(可以有多次转换)。
  3. 对Stream进行聚合操作,获取想要的结果,也可进行集合转换,得到想要的集合结果。

创建Stream

       创建Stream,常用的两种方式,1通过Stream接口的静态工厂方法;2通过Collection接口的默认方法–stream(),把一个Collection对象转换成Stream。

转化Stream

        转换Stream其实就是把一个Stream通过某些行为转换成一个新的Stream。Stream接口中定义了几个常用的转换方法:

       1. distinct: 对于Stream中包含的元素进行去重操作(去重逻辑依赖元素的equals方法),新生成的Stream中没有重复的元素;

       2. filter: 对于Stream中包含的元素使用给定的过滤函数进行过滤操作,新生成的Stream只包含符合条件的元素;

       3.map: 对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。这个方法有三个对于原始类型的变种方法,分别是:mapToInt,mapToLong和mapToDouble。这三个方法也比较好理解,比如mapToInt就是把原始Stream转换成一个新的Stream,这个新生成的Stream中的元素都是int类型。之所以会有这样三个变种方法,可以免除自动装箱/拆箱的额外消耗;

      4.flatMap:和map类似,不同的是其每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到父集合中;

      5.peek: 生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数;

      6. limit: 对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素;

      7. skip: 返回一个丢弃原Stream的前N个元素后剩下元素组成的新Stream,如果原Stream中包含的元素个数小于N,那么返回空Stream;

走一波试试:

List nums = new ArrayList(){
    {
        add(1);
        add(null);
        add(2);
        add(3);
        add(null);
        add(5);
        add(3);
        add(3);
        add(null);
        add(5);
    }
};
System.out.println("sum is:"+nums.stream().filter(num -> num != null).distinct().mapToInt(num -> num *2).peek(System.out::println).skip(2).limit(4).sum());

        这波先将nums进行非空过滤,留下所有非空元素,然后对于留下非空元素进行去重,然后再每个元素乘以2,再每个元素被消费的时候打印自身,在跳过前两个元素,最后去前四个元素进行加和运算。当然啦,前四个元素不够就有几个算几个啦。

性能问题:

        有些细心的同学可能会有这样的疑问:在对于一个Stream进行多次转换操作,每次都对Stream的每个元素进行转换,而且是执行多次,这样时间复杂度就是一个for循环里把所有操作都做掉的N(转换的次数)倍啊。其实不是这样的,转换操作都是lazy的,多个转换操作只会在汇聚操作(见下节)的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在汇聚操作的时候循环Stream对应的集合,然后对每个元素执行所有的函数。

        Stream接口有一些通用的汇聚操作,比如reduce()和collect();也有一些特定用途的汇聚操作,比如sum(),max()和count()。注意:sum方法不是所有的Stream对象都有的,只有IntStream、LongStream和DoubleStream是实例才有。

你可能感兴趣的:(积累)