问题:ArrayList和LinkedList的区别
难度:★★★★
工资提升度:★★☆
博主精选答案:
一、接口的默认方法
Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用default关键字即可,这个特征又叫做扩展方法,示例如下:
代码如下:
interface Formula { double calculate(int a);
default double sqrt(int a) { return Math.sqrt(a); } }
Formula接口在拥有calculate方法之外同时还定义了sqrt方法,实现了Formula接口的子类只需要实现一个calculate方法,默认方法sqrt将在子类上可以直接使用。
代码如下:
Formula formula = new Formula() { @Override public double calculate(int a) { return sqrt(a * 100);}};formula.calculate(100);1/ 100.0 formula.sqrt(16);//4.0
文中的formula被实现为一个匿名类的实例,该代码非常容易理解,6行代码实现了计算sqrt(a *100)。在下一节中,我们将会看到实现单方法接口的更简单的做法。
译者注:在Java中只有单继承,如果要让一个类赋予新的特性,通常是使用接口来实现,在C++中支持多继承,允许一个子类同时具有多个父类的接口与功能,在其他语言中,让一个类同时具有其他的可复用代码的方法叫做mixin。新的Java 8的这个特新在编译器实现的角度上来说更加接近Scala的trait。在C#中也有名为扩展方法的概念,允许给已存在的类型扩展方法,和ava 8的这个在语义上有差别。
二、Lambda表达式
首先看看在老版本的Java中是如何排列字符串的:代码如下:
List<string> names = Arrays.asList(""peterF"", "anna", "mike", ""xenia");
Collections.sort(names, new Comparator<string>(){ @override public int compare(String a, String b){return b.compareTo(a); } 3);
只需要给静态方法Collections.sort传入一个List对象以及一个比较器来按指定顺序排列。通常做法都是创建一个匿名的比较器对象然后将其传递给sort方法。
在Java 8中你就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式:代码如下:
Collections.sort(names,(String a, String b)-> { return b.compareTo(a); });看到了吧,代码变得更段且更具有可读性,但是实际上还可以写得更短:代码如下:
Collections.sort(names, (String a, String b)-> b.compareTo(a));
对于函数体只有一行代码的,你可以去掉大括号(以及return关键字,但是你还可以写得更短点:代码如下:
Collections.sort(names, (a, b)-> b.compareTo(a));
Java编译器可以自动推导出参数类型,所以你可以不用再写一次类型。
三、函数式接口
Lambda表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。而"函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为默认方法不算抽象方法,所以你也可以给你的函数式接口添加默认方法。
我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,你只需要给你的接口添加@Functionallnterface注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。
示例如下:代码如下:
@Functionallnterface interface Converter<F,T> { T convert(F from); } Converter<String, Integer> converter=(from) -> Integer.valueOf(from); Integer converted = converter.convert("123"");
System.out.printIn(converted); ll 123
需要注意如果@Functionallnterface如果没有指定,上面的代码也是对的。
译者注将lambda表达式映射到一个单方法的接口上,这种做法在Java 8之前就有别的语言实现,比如RhinoJavaScript解释器,如果一个函数参数接收一个单方法的接口而你传递的是一个function,Rhino解释器会自动做一个单接口的实例到function的适配器,典型的应用场景有org.w3c.dom.events.EventTarget的
addEventListener第二个参数EventListener。
四、方法与构造函数引用
前一节中的代码还可以通过静态方法引用来表示:代码如下:
Converter<String, Integer> converter = Integer:valueOf; Integer converted = converter.convert("123");System.out.printIn(converted); 1/ 123
Java 8允许你使用:关键字来传递方法或者构造函数引用,上面的代码展示了如何引用一个静态方法,我们也可以引用一个对象的方法:
代码如下:
converter = something:startsWith; String converted = converter.convert("Java");System.out.printIn(converted); 11 "”
接下来看看构造函数是如何使用::关键字来引用的,首先我们定义一个包含多个构造函数的简单类:代码如下:
class Person { String firstName; String lastName;Person()0
person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } }接下来我们指定一个用来创建Person对象的对象工厂接口:
代码如下:
interface PersonFactory<P extends Person> { P create(String firstName, String lastName); }
这里我们使用构造函数引用来将他们关联起来,而不是实现一个完整的工厂: