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

2020-06-15  本文已影响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();

匿名类的使用注意

匿名类跟局部类很相似

匿名类的常见用途

代码传递
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();
}
    (参数列表) -> {
      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的使用注意

@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);
 }

}

上一篇下一篇

猜你喜欢

热点阅读