Java

Lambda表达式

2020-05-08  本文已影响0人  张明学

本篇文单主要介绍Lambda表达式,在介绍Lambda表达式之前,需要了解一下接口的静态方法,接口的默认方法,函数式接口、方法引用。Lambda表达式是建立在此基础上,这些也都是JDK1.8引入进来的。

接口的静态方法

接口的静态方法就是,直接在接口类中用static修饰的实现方法。该方法不能被实现类重写,也不能被实现类调用。

public interface Hello {
    /**
     * 接口中定义的static方法
     */
    static void printHello() {
        System.out.println("Hello");
    }
}

调用方式,直接用接口类.方法名()。而接口的实现类HelloImpl是没有printHello方法的。

/**
 * 测试接口的Static方法
 */
 @Test
 public void testStatic() {
    Hello.printHello();
 }

接口的默认方法

接口的默认方法就是,直接在接口类中用default修饰的实现方法,该方法可以被接口的实现类重写。

public interface Hello {
    /**
     * 在接口中定义的default
     */
    default void talk() {
        System.out.println("default talk");
    }

    default void talk2() {
        System.out.println("default talk2");
    }

}

接口的实现类中重写其中的talk2方法

public class HelloImpl implements Hello {
    /**
     * 重写接口中的default方法
     */
    @Override
    public void talk2() {
        System.out.println("talk2");
    }
}

调用:

/**
     * 测试接口的默认方法
     */
    @Test
    public void testDefault() {
        Hello hello = new HelloImpl();
        hello.talk();
    }

    /**
     * 测试接口的默认方法
     */
    @Test
    public void testDefault2() {
        Hello hello = new HelloImpl();
        hello.talk2();
    }

结果:

default talk
talk2

函数式接口-@FunctionalInterface

函数接口的定义如下:仅含有一个抽象方法的接口 两个关键条件 1、是一个接口 2、只有一个抽象方法。这个抽象方法不包括equals方法,当然接口的静态方法和默认方法都不是抽象方法,也就是说函数式接口可以用static和default方法。如果满足:1、是一个接口 2、只有一个抽象方法。可以在接口类上面添加@FunctionalInterface注解。

@FunctionalInterface
public interface Glue {
    /**
     * 返回一个由arg1连接arg2的字符串
     *
     * @param arg1
     * @param arg2
     * @return
     */
    String link(String arg1, String arg2);

}

Glue就是一个函数式接口,如果仅包含static、default方法或equals方法也可以。说明一下,不是因为添加了@FunctionalInterface注解就是函数式接口,@FunctionalInterface注解是编译检查用的。只要仅含有一个抽象方法的接口就是函数式接口。

Lambda是什么?

个人理解,Lambda就是一个匿名的函数式接口实现类

@Test
public void test1() {
     Glue glue = (arg1, arg2) -> {
        return arg1 + "_" + arg2;
     };

     String result = glue.link("a","b");
     System.out.println(result);
}

结果:

a_b

简单说明一下:()->{} ()部分就是函数式接口中仅有的一个方法的形参,如果没有形参()中间就不需要形参名,{}部分就是函数式接口中仅有的一个方法的实现。如果有返回值就需要return,如果没有返回值就不需要,如果方法的实现只有一行代码并且有返回值,也可以不需要{}

上例也可以这个执行:

@Test
    public void test1() {
        Glue glue = (arg1, arg2) -> arg1 + "_" + arg2;
        String result = glue.link("a","b");
        System.out.println(result);
    }

无形参数函数式接口示例:

@FunctionalInterface
public interface Glue {
    
    void print();
}

@Test
public void test1() {
    Glue glue = () -> {
        System.out.println("Glue函数式接口的维一抽象方法print的实现");
    };
    glue.print();
}

另一个例子,JDK自带的Runnable接口也是一个FunctionalInterface

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

开启一个子线程也可以这样:

@Test
public void testRunnable1(){
    Runnable runnable = ()->{
        System.out.println("Runnable接口的run实现"+Thread.currentThread().getName());
    };
    new Thread(runnable).start();
}

@Test
public void testRunnable2(){
    new Thread(()->{
         System.out.println("Runnable接口的run实现"+Thread.currentThread().getName());
    }).start();
}

方法引用

方法引用分为普通方法引用和静态方法引用,普通方法引用为:对象名::方法,静态方法引用为:类::方法。它用在函数式接口的唯一抽象方法实现中。
定义一个普通的方法:

public class RandomNumImpl {
    /**
     * 产生一个随机数
     */
    public void buildNum() {
        Random random = new Random();
        System.out.println(random.nextInt(10));
    }
}

定义一个函数式接口Glue

@FunctionalInterface
public interface Glue {
    
    void print();
}

如果用Lamabe来表示一个函数式接口Glue的匿名实现类,并且print方法的实现还需要用到RandomNumImpl类,常用的写法是:

@Test
public void test2() {
    RandomNumImpl randomNum = new RandomNumImpl();
    Glue glue = () -> {
        randomNum.buildNum();
    };
    glue.print();
}

也可以简化成:

@Test
public void test3() {
    RandomNumImpl randomNum = new RandomNumImpl();
    Glue glue = randomNum::buildNum;
    glue.print();
}

如果把函数式接口Glue的唯一抽象方法print的实现改成需要调一个类的静态方法,还可以简化成:

public class RandomNumImpl {

    public static void buildLongNum() {
        Random random = new Random();
        System.out.println(random.nextLong());
    }

} 

@Test
public void test4() {
    Glue glue = RandomNumImpl::buildLongNum;
    glue.print();
}

小结一下: A::B A表示Lamada将要实现的抽象方法所需外部变量名,B表示A的某个方法,如果是静态方法,A则为了类名。

上一篇 下一篇

猜你喜欢

热点阅读