美文网首页
Java-05 匿名类、Lambda、方法引用

Java-05 匿名类、Lambda、方法引用

作者: 哆啦_ | 来源:发表于2020-06-15 19:18 被阅读0次

    匿名类(Anonymous Class)

    • 接口抽象类的实现类,在整个项目中只使用过一次,可以考虑使用匿名类
    // Person per = new Person();
        // per.run();// Person Run
    
        // 如果一个类只在一个地方使用、 可以使用匿名类
        Runable person = new Runable() {
          @Override
          public void run() {
            System.out.println("Person run");
          }
        };
    
        person.run();
    
        // 如果需要初始化之后立即执行某个函数 可以
        new Runable() {
          @Override
          public void run() {
            System.out.println("Person run");
          }
        }.run();
    
    

    匿名类的使用注意

    匿名类跟局部类很相似

    • 匿名类不能定义除了编译时常量之外的static成员
    • 匿名类只能访问final或者有效final的局部变量
    • 匿名类可以直接访问外部类的所有成员(包括private成员)
    • 匿名类只有在实例相关的代码块中才能直接访问外部类的实例成员(实例变量、实例方法)
    • 匿名类不能自定义构造方法,但可以有初始化块

    匿名类的常见用途

    代码传递
    public interface MyBlock {
      void execute();
    }
    
    public class Times {
      // 计算代码耗时
      public static void test(MyBlock block){
        long begin = System.currentTimeMillis();
        block.execute();
        long end = System.currentTimeMillis();
    
        double duration = (end - begin) / 1000.0;
        System.out.println("耗时:" + duration + "s");
      }
    }
    
       Times.test(new MyBlock(){
          @Override
          public void execute() {
            int age = 10;
            for (int i = 0; i < age; i++) {
              System.out.println(i);
            }
          }
        });
    
    
    
    回调

    类似于OC中的回调

    public interface NetBlock {
      void success(Object response);
      void failure();
    }
    
    public class Network {
      public static void get(String url, NetBlock callBack){
        // 模仿一个url请求
        boolean res = true;
        if (res) {
          Object resp = null;
          callBack.success(resp);
        } else {
          callBack.failure();
        }
      }
    }
    
    Network.get("https://xxxxx", new NetBlock(){
          @Override
          public void success(Object response) {
            System.out.println("请求成功");
          }
    
          @Override
            public void failure() {
              System.out.println("请求失败");
            }
        });
    
    过滤器

    匿名函数可以实现类似于filter的功能

    Lambda

    Lambda表达式是Java 8 开始有的语法

    函数式接口(Functional Interface):只包含一个抽象方法的接口

    @FunctionalInterface // 表示这是一个函数式接口
    public interface Testable {
      void test();
    }
    
    • 当匿名类实现的是函数式接口时,可以使用lambda来简化
        (参数列表) -> {
          reture xxx;
        } 
    
    // 普通写法
        Times.test(new MyBlock(){
          @Override
          public void execute() {
            int age = 10;
            for (int i = 0; i < age; i++) {
              System.out.println(i);
            }
          }
        });
    
        // lambda表达式
        
        Times.test(() -> {
          int age = 10;
            for (int i = 0; i < age; i++) {
              System.out.println(i);
            }
        });
    
    
    

    Supplier的使用

    有时使用Supplier传参,可以避免代码的浪费执行(有必要时再执行代码)

      public static void main(String[] args) {
        getFirstNotEmptyString("jack", makeString());
      }
      static String makeString() {
        return String.format("%d %d %d", 1, 2, 3);
      }
      static String getFirstNotEmptyString(String s1, String s2) {
        if (s1 != null || s1.length() != 0) return s1;
        if (s2 != null || s2.length() != 0) return s2;
        return null;
      }
    

    上面的示例中,我们确定了第一个参数不为空,也就没必要执行第二个参数的代码,但是现在makeString方法仍然会被调用。

    可以考虑使用Supplier这个函数式接口

      public static void main(String[] args) {
        getFirstNotEmptyString("jack", makeString());
        getFirstNotEmptyString("jack", new Supplier<String>() {
          @Override
          public String get() {
            return makeString();
          }
        });
        // lambda简化
        getFirstNotEmptyString("jack", () -> makeString());
      }
      static String makeString() {
        return String.format("%d %d %d", 1, 2, 3);
      }
      // 第二个参数的代码会执行
      static String getFirstNotEmptyString(String s1, String s2) {
        if (s1 != null || s1.length() != 0) return s1;
        if (s2 != null || s2.length() != 0) return s2;
        return null;
      }
    
      static String getFirstNotEmptyString(String s1, Supplier<String> s2Supplier ) {
        if (s1 != null || s1.length() != 0) return s1;
        String s2 = s2Supplier.get();
        if (s2 != null || s2.length() != 0) return s2;
        return null;
      }
    

    Lambda的使用注意

    • lambda只能访问final或者有效final的局部变量
    • Lambda没有引入新的作用域
    @FunctionalInterface
    public interface Testable {
      void test(int v);
    }
    
    public class OuterClass {
      private int age = 1;
      public class InnerClass {
        private int age = 2;
        void innerTest() {
          Testable t = v -> {
            System.out.println(v);  // 3
            System.out.println(age); // 2
            System.out.println(this.age); // 2
            System.out.println(InnerClass.this.age); // 2
            System.out.println(OuterClass.this.age); // 1
          };
    
          // 由于Lambda没有引入新的作用域 所以表达式里的代码有些类似于直接写在表达式的外面
          
          /* 类似于把代码写在这里
            System.out.println(v);  // 3
            System.out.println(age); // 2
            System.out.println(this.age); // 2
            System.out.println(InnerClass.this.age); // 2
            System.out.println(OuterClass.this.age); // 1
            */
          
          t.test(3);
        }
      }
    
      public static void main(String[] args) {
        new OuterClass().new InnerClass().innerTest();
      }
    }
    
    

    方法引用(Method Reference)

    如果Lambda中的内容仅仅是调用某个方法,可以使用方法引用

    种类 用法
    引用静态方法 ClassName::staticMethodName
    引用特定对象的实例方法 ObjectName::instanceMethodName
    引用特定类型的任意对象的实例方法 ClassName::methodName
    引用构造方法 ClassName::new
    引用当前类中定义的实例方法 this::instanceMethodName
    引用父类中定义的实例方法 super::instanceMethodName

    方法引用本质是一个语法糖,其本质还是那么复杂

    public interface Testable {
     int test(int v1, int v2);
    }
    
    public class Main {
     public static void main(String[] args) {
       // lambda表达式
       Testable t1 = (v1, v2) -> {
         return Math.max(v1, v2);
       };
       // 稍微精简下
       Testable t2 = (v1, v2)-> Math.max(v1, v2);
    
       // 使用方法引用简化
       Testable t3 = Math::max;
    
       System.out.println(t1.test(30, 50)); // 50
       System.out.println(t2.test(30, 50)); // 50
       System.out.println(t3.test(30, 50)); // 50
    
     }
    }
    

    引用特定对象的实例方法

    public interface Testable {
     void test(int v);
    }
    public class Person {
     public void setAge(int age) {
       System.out.println("Person - age = " + age);
     }
    }
    
    
    
    public class Main {
     static void execute(Testable t, int v) {
       t.test(v);
     }
     public static void main(String[] args) {
       // 
       execute(v -> new Person().setAge(v),10);
       // 
       execute(new Person()::setAge, 10);
     }
    
    }
    
    

    相关文章

      网友评论

          本文标题:Java-05 匿名类、Lambda、方法引用

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