java8之Lambda知识回顾

作者: DevSiven | 来源:发表于2018-01-05 15:05 被阅读118次

    前提

    18年第一篇文章,祝各位新年快乐哈~

    介绍Lambda之前,可以看下我们定义View点击事件的一般做法

      1. new View(this).setOnClickListener(new View.OnClickListener() {
      2.          @Override
      3.         public void onClick(View view) {
      4.              //...
      5.          }
      6.      });
    

    这种回调模式在日常开发中很常见,但是随之也暴露了一些不良的弊端
    1、非抽象化,整个代码有五行,其实实际逻辑只有在onclick里面,其他并不关心
    2、无法使用外部非final属性(这个遇到最多了)
    3、this指针意义不明确
    4、等等

    所以,java8特性Lambda正好解决了这一系列问题,以下

    new View(this).setOnClickListener(view->{
                //.. doing
            });
    

    1.引入的lambda

    lambda是在java8引入的函数表达式,其实是一种匿名的表达方式,Lambda表达式语法由参数列表->函数体组成。函数体既可以是一个表达式也可以是一个代码块。
    例如以下

     # 表达式
    ()->8; // 这里8是return的返回结果,简化了return
    
    #代码块
    ()->{
      //... 函数体
    }
    

    2.案例

    说多不如做多,现在举个🌰

    2.1 线程利用lambada表达式
    new Thread(()->{
                //这里是线程运行的区域,实质是抽象化了Runnable的run方法
                Log.i(TAG,"Thread is running...");
    }).run();
    
    2.2 多种情况利用lambada表达式

    首先定义一个测试回调接口类

    /**
         * 这个类完全提供一些接口测试
         */
        static class LambdaProvider{
    
            TestInterface0 mTestInterface0; // 测试不带参数与不带返回值
            TestInterface1 mTestInterface1;// 测试带返回值
            TestInterface2 mTestInterface2;// 测试待返回值、带参数
            TestInterface3 mTestInterface3;//测试抛出异常方法
    
            public void setmTestInterface0(TestInterface0 mTestInterface0) {
                this.mTestInterface0 = mTestInterface0;
            }
    
            public void setmTestInterface1(TestInterface1 mTestInterface1) {
                this.mTestInterface1 = mTestInterface1;
            }
    
            public void setmTestInterface2(TestInterface2 mTestInterface2) {
                this.mTestInterface2 = mTestInterface2;
            }
    
            public void setmTestInterface3(TestInterface3 mTestInterface3) {
                this.mTestInterface3 = mTestInterface3;
            }
    
            public interface TestInterface0{
                // 不带参数、不带返回值
                public void method();
            }
    
            public interface TestInterface1{
                // 带返回值
                public int method1();
            }
    
            public interface TestInterface2{
                // 带参数
                public int method2(int x);
            }
    
            public interface TestInterface3{
                // 抛出异常方法
                public void method3() throws Exception;
            }
    
        }
    

    测试代码

            String value="";
            LambdaProvider mLambdaProvider = new LambdaProvider();
            mLambdaProvider.setmTestInterface1(()->2); // 直接返回2
            mLambdaProvider.setmTestInterface1(()-> 2+4 ); // 直接返回计算表达式
            mLambdaProvider.setmTestInterface1(()->{ // 直接返回作用域
                Log.i(TAG,"setmTestInterface1 here...");
                //... do something
                String str = value; // 不用final就可以访问到了
                this.demo(); // this指针不再模糊
                return 3;
            });
    
            // # 3 针对参数+返回值利用lambada表达式
            mLambdaProvider.setmTestInterface2((x)->2); // 直接返回2
            mLambdaProvider.setmTestInterface2((x)-> 2+4 ); //x 直接返回计算表达式
            mLambdaProvider.setmTestInterface2((x)->{ // 使用形参x计算后返回
                return x+2+4;
            });
    
            // #4 针对会抛出异常
            mLambdaProvider.setmTestInterface3(()->{
                throw new IllegalStateException("hi~");
            });
    

    3.高效的 Stream api

    如果应用最小支持sdk24以上,Stream是非常高效的事情。当然国内sdk24以上的并不是占绝大多数,但是我们也可以先了解高效的Stream。
    先小试牛刀,一般foreach遍历list,我们一般会这么做

            List<String> listSteam = Arrays.asList("0","1","2");
            for (String i:listSteam){
                //...
            }
    

    利用steam api,我们可以这么做

           listSteam.forEach(i->{
                //...
            });
    

    反正我是佩服的😢

    什么是Stream?

    借鉴某大神的说明,“Stream不是集合元素,它也不是数据结构、不能保存数据,它更像一个更高级的Interator。Stream提供了强大的数据集合操作功能,并被深入整合到现有的集合类和其它的JDK类型中。流的操作可以被组合成流水线(Pipeline)”

    使用Stream可以做很多事情,如果以后会接触到rxjava,你会发现很多操作符是借鉴了Stream里面流的概念。在Stream操作中,都会涉及一个步骤

    上流(Stream)->处理->下流结果(Stream)
    

    举个例子🌰
    首先创建一个测试model,并且实例了一个数组

    class Model{
                public String type;//"1","2" 用于区别类型
                public String name;
                public Model(String type, String name) {
                    this.type = type;
                    this.name = name;
                }
    
                @Override
                public String toString() {
                    return "Model (type: " + type +" name: "+name+")";
                }
            }
    
     List<LambdaProvider.Model> listSteam = Arrays.asList(new LambdaProvider.Model("1","siven0"),
                    new LambdaProvider.Model("2","siven1"),new LambdaProvider.Model("2","siven2")
                    ,new LambdaProvider.Model("2","siven3"));
    
    

    场景1:

    只提取type是2的数据到新数组

      List<LambdaProvider.Model> newList = listSteam.stream()
                                                    .filter(s->s.type.equals("2"))
                                                    .collect(Collectors.toList());
      newList.forEach(s-> consoleInput(TAG,"stream newList: "+s));
    

    Collectors是负责接收上面传递过来的流,tolist是将传递过来的流重新组合成list
    filter是负责过滤上面传递过来的流,里面return是一个布尔值

    场景2:

    提取ype是2的数据,并且将流转化为其他数据的流后组成新的数组

    List<String> listIndex = listSteam.stream()
                                      .filter(s->s.type.equals("2"))
                                      .map(s->s.name)
                                      .collect(Collectors.toList());
            listIndex.stream().forEach(s-> consoleInput(TAG,"stream listIndex: "+s));
    

    map组要做流转化,上面的场景是接收到Model的流后,通过访问实体的对象name转化为字符串流(下面用map我会贴更加详细的说明)

    map的各种玩法(建议阅读):

            // 玩玩map转化
            List<String> stringList = Arrays.asList("1","2","3"); // 随便申请一个list
    
            consoleInput(TAG,"玩玩map转化 ----- flatmap ");
            List<String> tmp0  =  stringList.stream()
                    .flatMap((s)->{
                        String str = (String) s + " - 转化(flatmap)";
                        consoleInput(TAG,"转化前 "+s + ",转化后 " + str);
                        List<String> result = new ArrayList<>();
                        result.add(str);
                        return result.stream();
                    })
    //                  为了方便读者阅读,我用非lambda表达式
    //                  .flatMap(new Function<String, Stream<String>>() {
    //                      @Override
    //                      public Stream<String> apply(String s) {
    //                          String str = (String) s + " - 转化";
    //                          consoleInput(TAG,"转化前 "+s + "转化后 " + str);
    //                          List<String> result = new ArrayList<>();
    //                          result.add(str);
    //                          return result.stream();
    //                      }
    //                  })
                    .collect(Collectors.toList());// 流收集起来
            consoleInput(TAG,"转换后结果输出 ");
            tmp0.stream().forEach(c->consoleInput(TAG,"-> "+c));
    
            consoleInput(TAG,"玩玩map转化 ----- map ");
            tmp0 = stringList.stream()
                    .map((s)->{
                        String str = (String) s + " - 转化(map)";
                        consoleInput(TAG,"转化前 "+s + ",转化后 " + str);
                        return str;
                    })
    //                  为了方便读者阅读,我用非lambda表达式
    //                .map(new Function<String, String>() {
    //                    @Override
    //                    public String apply(String s) {
    //                        String str = (String) s + " - 转化(map)";
    //                        consoleInput(TAG,"转化前 "+s + ",转化后 " + str);
    //                        return str;                    }
    //                })
                    .collect(Collectors.toList());// 收集
            consoleInput(TAG,"转换后结果输出 ");
            tmp0.stream().forEach(c->consoleInput(TAG,"-> "+c));
    
            consoleInput(TAG,"玩玩map转化 ----- sum ");
            int sum = stringList.stream()
                    .mapToInt(s->Integer.valueOf(s)) // map转int
                    .sorted() // 排序
                    .sum();
            consoleInput(TAG,"转换后结果输出 "+sum);
    

    这里要思考的就是flatMap与map有什么区别了,从方法看flatMap是object->stream<T>。而map是object->object。如果你的场景是希望自己的上流传递有多次处理逻辑,并不希望马上得到下流的结果。那flatMap更满足你需求了。如果是直接A到B,明确的结果,map也许更适合你

    4.总结

    年终了~祝大家工作顺利,事业进步!
    by siven

    2018.1.5

    相关文章

      网友评论

        本文标题:java8之Lambda知识回顾

        本文链接:https://www.haomeiwen.com/subject/cxtdnxtx.html