zoukankan      html  css  js  c++  java
  • Java Lambda 表达式

    Java Lambda表达式

    Lambda 表达式被使用作提供一个功能接口的具体实现。节约代码。

    在表达式中,不需要再定义方法提供实现,只需要编写具体实现的方法。

    Lambda表达式会被视为一个函数,因此编译器不会创建.class文件

    方法接口

    在Lambda表达式中,提供了方法接口的实现方式。如果一个接口只有一个抽象方法就可以称作是方法接口。

    Java中提供了一个注解 @FunctionalInterface,可以用它声明方法接口。

    语法

    (argument-list) -> {body}
    

    一个表达式主要包含三部分:

    • Argument-list :变量清单(可以为空)
    • Arrow-token:箭头
    • body:包含lambda表达式和语句

    常用方式

    (p1) -> {  
    //只有一个参数,不需要指定类型,可以不用括号
    }  
    () -> {  
     System.out.println("Hello World");
    }  
    (p1,p2) -> {  return p1 + p2; }
    (p1,p2) -> p1+p2; 
    //上面两种情况相同,只有一句返回值时,不需要return和大括号
    //如果表达式正文只有一条语句,则必须包含在大括号中,返回类型也要和匿名返回类型相同
    () -> { return 3.1415 };
    

    方法引用

    双冒号::操作符是Java中的方法引用。当使用方法引用时,目标引用方法::之前,目标引用提供的方法名放在::之后,即目标引用::方法

    Person::getAge;
    

    Function 对象进行操作

    // 获取 getAge 方法的 Function 对象
    Function<Person, Integer> getAge = Person::getAge;
    // 传参数调用 getAge 方法
    Integer age = getAge.apply(p);
    

    目标引用的参数类型是 Function<T,R>T 表示传入类型,R 表示返回类型。

    比如,表达式 person -> person.getAge();,传入参数是 person,返回值是 person.getAge(),那么方法引用 Person::getAge 就对应着 Function<Person,Integer> 类型。

    使用示例

    public class Java8Tester {
       public static void main(String args[]){
          Java8Tester tester = new Java8Tester();
            
          // 类型声明,参数类型的声明需要保持一致,即全部同时声明或不声明
          MathOperation addition = (int a, int b) -> a + b;
            
          // 不用类型声明
          MathOperation subtraction = (a, b) -> a - b;
            
          // 大括号中的返回语句
          MathOperation multiplication = (int a, int b) -> { return a * b; };
            
          // 没有大括号及返回语句。只有一句的时候,可以不包含return关键字
          MathOperation division = (int a, int b) -> a / b;
            
          System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
          System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
          System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
          System.out.println("10 / 5 = " + tester.operate(10, 5, division));
            
          // 不用括号
          GreetingService greetService1 = message ->
          System.out.println("Hello " + message);
            
          // 用括号
          GreetingService greetService2 = (message) ->
          System.out.println("Hello " + message);
            
          greetService1.sayMessage("Runoob");
          greetService2.sayMessage("Google");
           
           //循环
           List<String> list1 = Arrays.asList("hello","good");
           list1.forEach(
                    (n) -> System.out.println(n)
           );
       }
       interface MathOperation {
          int operation(int a, int b);
       }
       interface GreetingService {
          void sayMessage(String message);
       }
       private int operate(int a, int b, MathOperation mathOperation){
          return mathOperation.operation(a, b);
       }
    }
    

    注意

    变量作用域

    1. 如果一个参数声明了类型,则所有的参数都需要声明变量类型
    2. 在Lambda表达式的变量中,不能和函数中声明的临时变量重复

    Lambda表达式和匿名类的区别

    两者的主要区别在于关键词的使用。对于匿名类,关键词this解释为匿名类,但是对Lambda表达式,关键词this会被写作时Lambda的外部类。

    而造成这样的区别的主要原因就是两者的编译方法不同。Java编译器会编译Lambda表达式并将其转化为类中的私有函数,使用 Java 7 中新加的 invokedynamic 指令动态绑定该方法。参考

    常用场景

    1.创建线程对象

    public class ThreadTest{
        public static void main(){
            Runnable r1 = () -> {
                System.out.println("Thread1 is running ...");
            };
            Thread t1 = new Thread(r1);
            t1.start();
            Runnable r2 = () -> {
                System.out.println("Thread2 is running ...");
            };
            Thread t2 = new Thread(r2);
            t2.start();
        }
    }
    

    2.集合框架的使用

    Lambda表达式可以在集合框架中使用。可以提供高效简洁的方式实现迭代、过滤、获取数据。

    使用场景

    • 比较器 Comparator
    • 过滤器 Filter
    • 事件监听器 Event Listener
    public class collectionFrameWorkLambda {
        public static void main(String[] args) {
            List<Product> list = new ArrayList<>();
            //Adding Products
            list.add(new Product(1,"HP Laptop",25000f));
            list.add(new Product(3,"Keyboard",300f));
            list.add(new Product(2,"Dell Mouse",150f));
            //implementing lambda expression
            //Comparator 比较器
            Collections.sort(list,
                    (p1,p2)->(p1.name.compareTo(p2.name))
            );
            for (Product product : list) {
                System.out.println(product.id+" "+ product.name+" "+ product.price);
            }
            //Filter Collection Data 过滤器
            Stream<Product> productStream = list.stream().filter(product -> (product.price > 20000f));
            productStream.forEach(
                    product -> System.out.println(product.name+":"+product.price)
            );
            //Event Listener 事件监听
            JTextField tf = new JTextField();
            tf.setBounds(50, 50, 150, 20);
            JButton button = new JButton("click");
            button.setBounds(80, 100, 70, 30);
    
            // lambda expression implementing here.
            button.addActionListener(e -> tf.setText("hello swing"));
    
            JFrame f = new JFrame();
            f.add(tf);
            f.add(button);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setLayout(null);
            f.setSize(300, 200);
            f.setVisible(true);
        }
    }
    class Product {
        int id;
        String name;
        float price;
        public Product(int id, String name, float price) {
            this.id = id;
            this.name = name;
            this.price = price;
        }
    }
    

    参考:

  • 相关阅读:
    两种图像缩放算法的对比与实现
    字节流与字符流
    自己的网站 首都易搜网 又修改了一下。。首页改变了
    序列化和反序列化 .NET
    关于 C#异步方法的使用
    vs2010 设计视图中控件无法加载,提示未将对象设置到对象的实例。
    .Net 中的反射(查看基本类型信息) Part.2
    URL重写
    .Net 中的反射(序章) Part.1
    数据库死锁问题 及 解决方法
  • 原文地址:https://www.cnblogs.com/ginko/p/15173523.html
Copyright © 2011-2022 走看看