认识JDK8新特性之Lambda表达式

说来挺惭愧的,JDK8已经出来这么多年,在实际项目中却很少真正使用Lambda表达式。其实工作中的项目很早就从开发、测试、生产,全面使用JDK8+Tomcat8了。

所以看来是时候要重新认识下这个奇怪的东西。

没错,当第一次看到Lambda表达式时,我就认为这是个奇怪的东西,->写法让我感觉这是在写其它语言,说好的一切皆对象呢?

表达式语法

这是Lambda表达式的基本语法:

(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
    statment1;
    statment2;
    //......
    return statmentM;
}

参数列表是一个逗号分隔的形式参数列表,这些参数与功能接口中单一方法的形式参数相对应。指定参数类型是可选项;如果未指定参数类型,将从上下文推断。参数列表必须用括号括起来,但当指定的单一参数不带参数类型时除外;指定单一形式参数时可以不带括号。如果功能接口方法不指定任何形式参数,则必须指定空括号。

语句块必须包含在大括号内,除非语句块是一个方法调用语句。

举个简单例子

对于无参无返回值,可以有如下写法:

public interface TestIntf {
    public void sayHello();
}

// -> 前的一对小括号和后面的一对大括号都不能去掉。
TestIntf intf = () -> {System.out.println("HelloWorld!!!");};
intf.sayHello();

对于有参有返回值,可以有如下写法:

public interface TestIntf {
    public String sayHello(String word);
}

// 完整写法
TestIntf intf = (String word) -> {return "Hello " + word;};

// 参数word的类型可以推断时,可以去掉类型定义:
TestIntf intf = (word) -> {return "Hello " + word;};

// 甚至当参数只有一个时,可以去掉左边的小括号:
TestIntf intf = word -> {return "Hello " + word;};

// 右侧的方法体只有一个表达式时,可以去掉大括号,甚至连return都可以不要:
TestIntf intf = word -> "Hello " + word;

变量作用域

Lambda表达式内部可以访问外部的变量,但需要注意:

局部变量无论是在Lambda表达式主体中声明,还是在封闭作用域中声明,使用之前都必须先初始化。如:

interface TestIntf {
    public String sayHello(String word);
}

public class App {
    public static void main(String[] args) {
        String str;
        TestIntf intf = (String word) -> {
            System.out.println(str); // 编译失败,提示str变量未被初始化。
            return "Hello " + word;
        };
    }
}

Lambda表达式不会定义新的作用域;Lambda表达式的作用域与封闭作用域相同。如:

interface TestIntf {
    public String sayHello(String word);
}

public class App {
    public static void main(String[] args) {
        String str = "word";
        TestIntf intf = (String word) -> {
            String str = ""; // 编译失败,提示str变量重复定义了。
            return "Hello " + word;
        };
    }
}

而且也不能修改外部变量:

interface TestIntf {
    public String sayHello(String word);
}

public class App {
    public static void main(String[] args) {
        String str = "word";
        TestIntf intf = (String word) -> {
            str = "word!!!"; // 编译报错:Local variable str defined in an enclosing scope must be final or effectively final
            return "Hello " + word;
        };
    }
}

当然,引用变量是可以通过内部方法达到数据修改的。

interface TestIntf {
    public String sayHello(StringBuilder word);
}

public class App {
    public static void main(String[] args) {
        StringBuilder str = new StringBuilder("word");
        TestIntf intf = (StringBuilder word) -> {
            word.append("!!!");
            return "Hello " + word;
        };
        System.out.println(intf.sayHello(str)); // Hello word!!!
        System.out.println(str); // word!!!
    }
}

Lambda表达式中的this

在Lambda表达式中this引用的不是Lambda表达式对象,而是声明它的外部对象:

interface TestIntf {
    public String sayHello();
}

public class App {
    
    public void test() {
        TestIntf intf = () -> "Hello " + this.getClass().getSimpleName();
        System.out.println(intf.sayHello());
    }
    
    public static void main(String[] args) {
        App app = new App();
        app.test(); // Hello App
    }
}

参考文章

https://www.oracle.com/techne...

你可能感兴趣的:(jdk8,lambda,java)