為什么引入Lambda?
簡單的來說Lambda的引入是為了簡化匿名類的編寫
什么是Lambda表達式
- Lambda表達式就是個匿名方法伴网,就是說一個方法户辱,但是沒有定義名字卢肃,返回值,訪問修飾符
例1:
public void m1(){
System.out.println("Hello");
}
我們可以用Lambda表達式寫成如下的方式
() -> System.out.println("Hello");
() -> {System.out.println("Hello");}
例2:
public void m2(int a, int b){
System.out.println(a+b);
}
我們可以用Lambda表達式寫成如下的方式
(int a, int b) -> System.out.println(a+b);
(a, b) -> {System.out.println(a+b);}
例3:
public String m3(String name){
return "Hello " + name;
}
我們可以用Lambda表達式寫成如下的方式
(String name) -> return name;
(name) -> name;
Functional Interface
說到Lambda若未,我們必須要提下Functional Interface朱嘴, 那什么是Functional Interface呢?
- 簡單來說Functional interface只包含一個抽象方法粗合,這樣的一個解開我們稱之為Functional Interface萍嬉,其方法叫做Functional method 或者叫做simple abstract method (SAM)
如果查看Java source code,你會發(fā)現(xiàn)Runnable 就是個Functional Interface
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
在Functional Interface 里面除了只能定義一個SAM之外隙疚,你隨意定義多個default methods 還有static methods
@FunctionalInterface
你可以已經(jīng)看到了壤追,java8 為此定義了一個annotation,@FunctionalInterface, 被加了@FunctionalInterface的接口必須符合Functional interface的定義要求供屉,有且只能有一個SAM行冰, 否則會報錯,比如
@FunctionalInterface
public interface Interf {
public void m1();
}
上面的定義不會報錯,但是下面這兩個定義會抱編譯錯誤
@FunctionalInterface
public interface Interf {
public void m1();
public void m2();
}
@FunctionalInterface
public interface interf{
}
對于繼承接口伶丐,如果定義成Functional interface悼做,也是同樣的要求, 看下面的例子
@FunctionalInterface
public interface InterA {
public void m1();
}
@FunctionalInterface
public interface InterB extends InterA {
}
上面的定義是OK的撵割,但是下面的這個就會報編譯錯誤贿堰,原因很簡單,InterB 不符合有且只有一個SAM
@FunctionalInterface
public interface InterA {
public void m1();
}
@FunctionalInterface
public interface InterB extends InterA {
public void m2();
}
InterB 如何去掉@FunctionalInterface啡彬,那InterB是個普通的interface羹与,這個時候多定義幾個接口是OK的故硅,所以上面的那段代碼,InterB去掉@FunctionalInterface纵搁,那么編譯是可以通過的吃衅。
Functional Interface Vs Lambda
了解了Functional Interface, 來看看Functional Interface 跟Lambda 有什么關(guān)系腾誉。
一旦我們寫了一個Lambda 表達式去調(diào)用它的方法徘层, 那么就需要Functional Interface,我們知道當(dāng)我們寫Lambda的時候利职,我們不需要寫方法的名字趣效,那么我們到底是實現(xiàn)的哪個方法呢,這個時候就用到了Functional Interface的概念猪贪,能用Lambda寫匿名function的跷敬,必須是個Functional interface,因為它只能定義一個抽象接口热押,所以Lambda表達式就一定是實現(xiàn)的那個接口西傀。
例1: 傳統(tǒng)寫法
interface Interf {
public void method1() {}
}
public class Demo implements Interface {
public void method1() {
System.out.println(“method1 ”);
}
}
public class Test {
public static void main(String[] args) {
Interf i = new Demo();
i.method1();
) }
Lambda寫法
interface Interf {
public void method1() {}
}
public class Test {
public static void main(String[] args) {
Interf i = () -> System.out.println(“method1 ”);
i.method1();
) }
例2: 傳統(tǒng)寫法
class MyRunnable implements Runnable {
public void main() {
for(int i=0; i<10; i++) {
System.out.println(“Child Thread”);
}
}
}
class ThreadDemo {
public static void main(String[] args) {
Runnable r = new myRunnable();
Thread t = new Thread(r);
t.start();
}
}
Lambda寫法
class ThreadDemo {
public static void main(String[] args) {
Runnable r = () -> {
for(int i=0; i<10; i++) {
System.out.println(" for lambda child thread");
}
};
Thread t = new Thread(r);
t.start();
}
}
匿名內(nèi)部類 Vs Lambda表達式
我們同樣可以用Lambda來簡化匿名內(nèi)部類的寫法,如下的列子
傳統(tǒng)寫法
class ThreadDemo {
public static void main(String[] args) {
Thread t = new Thread( new Runnable(){
public void run(){
for(int i=0; i<10; i++) {
System.out.println(" Child thread");
}
}
});
t.start();
}
}
Lambda寫法
class ThreadDemo {
public static void main(String[] args) {
Thread t = new Thread(() -> {
for(int i=0; i<10; i++) {
System.out.println(" Child thread");
}
});
t.start();
}
}
我們可以看到Lambda表達式可以簡化匿名內(nèi)部類的書寫桶癣,可讀性更高些拥褂。
但是 匿名內(nèi)部類!=Lambda表達式:
-匿名內(nèi)部類可以extends普通的類牙寞,抽象類饺鹃,帶有任意多抽象方法的接口,但是Lambda表達式只能實現(xiàn)帶有一個抽象方法的接口
- 匿名內(nèi)部類可以聲明instance變量间雀;而Lambda不可以定義instance 變量尤慰,它定義的只是local 變量
- 在匿名內(nèi)部類里面this指的就是當(dāng)前的匿名內(nèi)部類; 而在Lambda表達式里面雷蹂,this指定的是外部類伟端,就是定義Lambda表達式的所在的那個類
Interface Interf{
public void m1();
}
public class Demo{
int i = 100;
public void m2(){
Interf i = () ->{
int i =200;
System.out.println(i); // print 200
System.out.println(this.i) // print 100
};
i.m1();
}
public static void main(String[] args) {
Demo demo = new Demo();
demo.m2();
}
}
? Lambda表達式,我們可以直接訪問外部的類變量匪煌,外部的方法變量
? 但是外部的方法里面定義的local變量责蝠,在lambda表達式里面是final的,就是說Lambda表達式不可以修改外部方法的local變量萎庭,否則會出現(xiàn)編譯錯誤霜医,見下面的列子:
@FunctionalInterface
public interface ForFunctionalInterface {
public void name() ;
}
class Test{
int yy = 77;
public void test() {
int tt = 100;
ForFunctionalInterface it = () ->{
int xx = 88;
System.out.println(xx);
System.out.println(tt);
System.out.println(yy);
xx = 11;
yy = 99;
tt = 200; // compile error
};
it.name();
}
}
總結(jié): 內(nèi)部類跟Lambda表達式的區(qū)別
匿名內(nèi)部類 | Labmda表達式 |
---|---|
匿名類 | 匿名方法 |
Anonymous inner class can extend Abstract and concrete classes | lambda expression can’t extend Abstract and concrete classes |
Anonymous inner class can implement An interface that contains any number of Abstract methods | lambda expression can implement an Interface which contains single abstract method (Functional Interface) |
Inside anonymous inner class we can Declare instance variables. | Inside lambda expression we can’t Declare instance variables, whatever the variables declared are simply acts as local variables. |
Anonymous inner classes can be Instantiated | lambda expressions can’t be instantiated |
Inside anonymous inner class “this”Always refers current anonymous Inner class object but not outer class Object. | Inside lambda expression “this” Always refers current outer class object. That is enclosing class object. |
Anonymous inner class is the best choice If we want to handle multiple methods. | Lambda expression is the best Choice if we want to handle interface With single abstract method (Functional Interface). |
In the case of anonymous inner class At the time of compilation a separate Dot class file will be generated(outerclass$1.class) | At the time of compilation no dot Class file will be generated for Lambda expression. It simply converts in to private method outer class. |
Memory allocated on demand Whenever we are creating an object | Reside in permanent memory of JVM (Method Area). |