Java8的新特性相对于前版本(Java7)来说,主要体现在两个方面:
1. 接口定义与使用
2. Lambda表达式对匿名内部类的简化使用。
Java8新特性的具体表现如下:
1.在接口中的体现
(1)在接口中可以定义实体方法,但除原先的抽象方法外只能定义两种方法:
A.公共的静态方法
如:
package com.jasberyon.java8.interfacer; public interface InterfaceA { public static void sayHi(){ System.out.println("InterfaceA---sayHi"); } }
需要注意的是:
a.由于静态方法是属于类(文件)的,所以调用时需要使用对应的接口(静态方法所在类)名去调用。所以在Java8中调用接口中静态方法时,只能通过接口名去调用,使用实现类是无法调用的。
B.使用default关键字声明的普通方法
如:
<span style="font-size:12px;">package com.jasberyon.java8.interfacer; public interface InterfaceA { public default void sayHi2(){ System.out.println("InterfaceA---sayHi2"); } } </span>
需要注意的是:
b.default关键字只能在接口中使用。那么当在接口的具体实现类中重写该default关键之标识的方法时就需要去掉default关键字。如:
package com.jasberyon.java8.interfacer; public class InterfaceImpl implements InterfaceA { public static void main(String[] args){ InterfaceA.sayHi(); InterfaceImpl.sayHi(); } public static void sayHi(){ System.out.println("InterfaceImpl---sayHi"); } public void sayHi2(){ System.out.println("InterfaceB---sayHi2"); } }
在上面的代码情况(重写接口中的default关键字标识的方法)下当多态调用时,同样会走现实类(子类)的方法,如果没有重写,则走接口中的default方法。
例如:
package com.jasberyon.java8.interfacer; public class InterfaceImpl implements InterfaceA { public static void main(String[] args){ InterfaceA.sayHi(); InterfaceImpl.sayHi(); InterfaceA ia = new InterfaceImpl(); ia.sayHi2(); } public static void sayHi(){ System.out.println("InterfaceImpl---sayHi"); } public void sayHi2(){ System.out.println("InterfaceB---sayHi2"); } }
输出结果:
InterfaceA---sayHi
InterfaceImpl---sayHi
InterfaceB---sayHi2
注意: 因为在Java中类是单继承的,而接口却是可以多实现的。这样这几的初衷是出于安全性的考虑。因为在多继承的模式中,如果子类C继承了父类A和B,而A和B中又有相同的方法methodAlike。那么这时就无法区分子类C中使用方法时到底是使用哪一父类中的方法了。而(原先的设计)接口则不同,实现类需要实现接口中定义的方法,则不存在上述的安全性问题。
那么,现在的问题是:由于在Java8的新特性中可以在接口中定义非静态的方法,那么当多个接口中定义了相同的非静态default方法时,如果实现类实现了这多个接口时,是不是就出现了多继承了呢?
答案是否定的
这时就会产生编译时错误,需要在实现类中覆盖相同的接口中定义的所有方法方法。
如:
定义接口InterfaceA
package com.jasberyon.java8.interfacer; public interface InterfaceA { public static void sayHi(){ System.out.println("InterfaceA---sayHi"); } public default void sayHi2(){ System.out.println("InterfaceA---sayHi2"); } }
定义接口InterfaceB
package com.jasberyon.java8.interfacer; public interface InterfaceB { public static void sayHi(){ System.out.println("InterfaceB---sayHi"); } public default void sayHi2(){ System.out.println("InterfaceB---sayHi2"); } }
那么此时就会发现接口InterfaceA和InterfaceB中有相同的方法:public
defaultvoidsayHi2(),那么此时实现类就必须去重写相同的方法。
实现类InterfaceImpl
package com.jasberyon.java8.interfacer; public class InterfaceImpl implements InterfaceA, InterfaceB { public static void sayHi(){ System.out.println("InterfaceImpl---sayHi"); } public void sayHi2(){ System.out.println("InterfaceB---sayHi2"); } }
小结:Java的接口本身就是一种为扩展程序而使用的,在Java8中应该避免让实现类去覆盖具有多个相同default方法的接口,这样没有什么意义。Java8在接口中的新特性仅作为一个扩展而使用。而对于接口中的静态方法,在实现类中去“重写”(实际上不是)是没有意义的。
2. Lambda表达式对匿名内部类的简化使用
Lambda表达式替换了原有的匿名内部类的写法,简化了匿名内部类的使用方式。当然简化的方式总是会使得功能使用时有所限制,Just like 增强型for(for-each)循环。
Lambda表达式的语法结构:
(参数1,参数2...)->{
重写方法内容,不写定义方法名。
}
(1)多线程时使用Lambda表达式
原来的使用匿名内部类实现多线程的栗子:
package com.jasberyon.java8.lambda; public class ThreadDemo { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { for(int i=0; i<200; i++){ System.out.println("执行run---------"+i); } } }).start(); for(int j=0; j<200; j++){ System.out.println("执行mian---------------"+j); } } }
使用Lambda表达式改造后:
package com.jasberyon.java8.lambda; public class ThreadDemo { public static void main(String[] args) { Runnable runnable = ()->{ for(int i=0; i<200; i++){ System.out.println("执行run---------"+i); } }; new Thread(runnable).start(); for(int j=0; j<200; j++){ System.out.println("执行mian---------------"+j); } } }
又或者这样写:
package com.jasberyon.java8.lambda; public class ThreadDemo { public static void main(String[] args) { new Thread(()->{ for(int i=0; i<200; i++){ System.out.println("执行run---------"+i); } }).start(); for(int j=0; j<200; j++){ System.out.println("执行mian---------------"+j); } } }
那么,Lambda的弊端也是显而易见的,如果接口中定义了多个抽象方法,那么就只能使用传统方式了。
(2)集合排序“比较器”中使用Lambda表达式
TreeSet会将字符串按照自然顺序进行排序,如下代码:
package com.jasberyon.java8.lambda; import java.util.Set; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { Set<String> set = new TreeSet<String>(); set.add("asdafa"); set.add("abcdefsadf"); set.add("sahdfoad"); set.add("bhsayuadasdfasdf"); set.add("auiweyqwergeawgfasdasd"); System.out.println(set); } }
结果输出:
[abcdefsadf, asdafa,auiweyqwergeawgfasdasd, bhsayuadasdfasdf, sahdfoad]
使用自定义的比较器后:
package com.jasberyon.java8.lambda; import java.util.Comparator; import java.util.Set; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { Set<String> set = new TreeSet<String>(new MyCompareMethod()); set.add("asdafa"); set.add("abcdefsadf"); set.add("sahdfoad"); set.add("bhsayuadasdfasdf"); set.add("auiweyqwergeawgfasdasd"); System.out.println(set); } } class MyCompareMethod implements Comparator<String>{ @Override public int compare(String o1, String o2) { int length = o1.length() - o2.length(); return length == 0?o1.compareTo(o2):length; } }
结果输出:
[asdafa, sahdfoad, abcdefsadf,bhsayuadasdfasdf, auiweyqwergeawgfasdasd]
使用匿名内部类后:
package com.jasberyon.java8.lambda; import java.util.Comparator; import java.util.Set; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { Set<String> set = new TreeSet<String>(new Comparator<String>(){ @Override public int compare(String o1, String o2) { int length = o1.length() - o2.length(); return length == 0?o1.compareTo(o2):length; } }); set.add("asdafa"); set.add("abcdefsadf"); set.add("sahdfoad"); set.add("bhsayuadasdfasdf"); set.add("auiweyqwergeawgfasdasd"); System.out.println(set); } }
使用Lambda表达式改造:
package com.jasberyon.java8.lambda; import java.util.Set; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { Set<String> set = new TreeSet<String>((String o1, String o2)->{ int length = o1.length() - o2.length(); return length == 0?o1.compareTo(o2):length; }); set.add("asdafa"); set.add("abcdefsadf"); set.add("sahdfoad"); set.add("bhsayuadasdfasdf"); set.add("auiweyqwergeawgfasdasd"); System.out.println(set); } }
也可写成:
package com.jasberyon.java8.lambda; import java.util.Set; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { Set<String> set = new TreeSet<String>((o1, o2)->{ int length = o1.length() - o2.length(); return length == 0?o1.compareTo(o2):length; }); set.add("asdafa"); set.add("abcdefsadf"); set.add("sahdfoad"); set.add("bhsayuadasdfasdf"); set.add("auiweyqwergeawgfasdasd"); System.out.println(set); } }
值得注意的是,此时需要泛型标注。也就是比较的类型必须在<>中声明,否则无法通过编译。
同时,使用Lambda表达式的实现不会再有额外的类文件(原来的方式匿名内部类也是要产生形如Ttt$xx.class的文件的)产生。
其它的还有很多就不在列举了。记住一点,构造匿名内部类时,如果只有一个方法需要重写,那么就可以使用Lambda表达式。
版权声明:本文为博主原创文章,未经博主允许不得转载。