美文网首页
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、方法引用

    匿名类(Anonymous Class) 当接口、抽象类的实现类,在整个项目中只使用过一次,可以考虑使用匿名类 匿...

  • 提示四十三

    提示四十三:方法引用优于 lambda 表达式。 lambda 优于匿名类的主要优点是它更简洁,而方法引用比它更简...

  • 第四十三条:方法引用优先于Lambda

    与匿名类相比,Lambda的主要优势在于更加简洁。Java提供了生成比Lambda更加简洁函数对象的方法:方法引用...

  • 第七章 函数接口,lambda和方法引用

    java8 函数接口,lambda和方法引用 第四十二条, lambda 优先于匿名类(lambda表达式)1.函...

  • lambda构造方法引用

    lambda表达式构造方法引用:使用匿名函数、lambda表达式分别进行测试 1、首先创建student类 2、然...

  • Java Optional 类

    改善代码可读性 重构代码,用Lambda表达式取代匿名类; 用方法引用重构Lambda表达式; 用Stream A...

  • 第七章Lambda表达式和Stream流

    目录 lambda表达式优于匿名类 方法引用优于lambda表达式 优先使用标准的函数式接口 明智审慎地使用Str...

  • 方法引用 ~ java8特性

    1. 介绍 前面讲的lambda表达式,已经简化了匿名类的写法,而我们使用方法引用结合lambda表达,可以更加简...

  • Java 匿名类、Lambda和方法引用

    匿名类 当接口、抽象类的实现类,在整个项目中只用过一次,可以考虑使用匿名类定义一个接口或抽象类public int...

  • java - 学习笔记

    日期 匿名类 lambda stringBuffer stringBuilder 定时 日期 匿名类 lambda...

网友评论

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

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