一、接口的默认方法
Java 8允许在接口中添加非抽象的方法实现,只需要使用default关键字即可,这个特征又叫做扩展方法,示例如下:
interface iNews{
List<News> getAllNews();
default int aadd(int a){
return a*100;
}
}
iNews接口的子类只需要实现getAllNews();
这个方法就可以了,默认就会带有getDate()
这个方法不需要再实现。
二、Lambda表达式
我先举一个例子,示例代码如下:
//定义一个stringlist
List<String> names = Arrays.asList("Lucy","XiaoMing","Mike");
//排序
Collections.sort(names,Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
老版本中的做法就是给静态方法Collections.sort方法传入一个list对象还有一个比较器来指定顺序排列。通常做法都是创建一个匿名的比较器对象然后传给sort方法。
但是在Java 8 中就没有必要再这样做了,Java8中提供了更加简洁的方式:Lambda表达式
直接上示例代码:
//定义一个stringlist
List<String> names = Arrays.asList("Lucy","XiaoMing","Mike");
//排序
Collections.sort(names,(String a,String b) ->{
return b.compareTo(a);
});
只用Lambda表达式代码变得更加简洁了,但是还可以变短,示例代码如下:
//排序
Collections.sort(name,(String a , String b) -> b.compareTo(a) );
如果函数体只有一行代码,那么可以直接去掉大括号{}还有return关键字,但实际上还可以更短
//排序
Collections.sort(name,(a,b) -> b.compareTo(a));
Java编译器可以自动推导出来参数类型,所以你可以不用再写参数类型。
三、函数式接口
Lambda表达式是如何在Java的类型系统中表示的呢?每一个Lambda表达式都表示对应一个类型,通常是接口类型。而函数式接口就是指只有一个抽象方法的接口,每一个该类型的Lambda表达式都会匹配到这个抽象方法。因为默认方法 不算抽象方法,所以你也可以给你的函数式接口添加默认方法。
默认方法指的就是Java8中的新特性——给接口添加一个默认方法,具体有在第一点讲到
我们可以将Lambda表达式当做任意一个只包含一个抽象方法的接口类型,确保你的接口达到了这个要求,可以使用一个注解:@FunctionalInterface ,这个注解的作用也是非常简单明了,把这个注解贴在接口上,如果这个接口有多余一个的抽象方法,就会报错。(再直白点,就是贴上了之后,这个接口只能有一个抽象方法,多了就报错)。
实例代码如下:
@FunctionalInterface
interface Converter<F,T>{
T convert(F from);
}
Converter<String,Integer> converter = (from) -> Integer.valueOf(from);
Integer converter = converter.convert("123");
System.out.println(converter); //结果为123
四、方法与构造函数
前一节的代码还可以通过静态方法来引用,示例代码如下:
Converter <String,Integer> converter = Integer::valueOf;
Integer converted = converter.convert("123");
System.out.println(converted);
Java8允许你使用::关键字来传递方法或者是构造函数的引用,上面的代码引用的是一个静态方法,我们还可以引用一个对象的方法,示例代码如下:
converter = something::startsWith;
String converted = converter.convert("java");
System.out.println(converted); //j
接下来来试试构造函数的引用,先创建一个具有多个构造函数的简单Java类,示例代码如下:
class Person{
String name;
Double money;
}
Person(){
}
Person(String name , Double money){
this.name = name;
this.money = money;
}
接下来指定一个用来创建Person对象的对象工厂接口,示例代码如下:
interface PersonFactory<P extends Person> {
P create(String name, Double money);
}
我们使用构造函数把他们关联起来,而不是实现一个完整的工厂,示例代码如下:
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("小明",1000.0);
我们使用的时候,只需要用Persion :: new来获取Person类的构造函数的引用,Java编译器会自动根据PersonFactory.create方法的签名来选择合适的构造函数。
五、访问局部变量
我们可以直接在lambda表达式中访问外层的局部变量,示例代码如下:
final int num = 1;
Converter<Integer,String> stringConverter = (from) ->String.valueOf(from+num);
stringConverter.convert("2"); //3
但是这里的 final int num
可以不用final 修饰,代码同样正确,但是如果去掉了final的话,num变量就不能被后面的代码修改(其实就是final了),如果被后面的代码修改了,代码就无法被编译。
六、访问对象字段与静态变量
和本地变量不同的是,lambda内部对于实例的字段以及静态变量是又可读又可写。
示例代码如下:
class lambda {
static int staticNum;
int num;
void test(){
Converter<Integer,String> stringConverter1 = (from) ->{
staticNum = 123;
return String.valueOf(from)
};
Converter<Integer,String> stringConverter2= (from) ->{
num = 123;
return String.valueOf(from)
};
}
}
七、访问接口的默认方法
还记得第一节的例子吗?一个接口除了抽象方法,还可以定义一个默认方法,这个方法可以被它的实例对象或者是匿名对象访问,但是这个在Lambda中是不行的。
Java8 API提供了很多全新的函数式接口让工作更加方便:
-
Predicate接口
Predicate接口只有一个参数,返回boolean类型,其中包含了很多默认方法来组成复杂的逻辑
示例代码如下:
Predicate<String> predicate = (s) -> s.length() > 0 ;
predicate.test("foo"); //true
predicate.negate().test("foo"); // false
Predicate<Boolean> nonNull = Objects::nonNull;
Predicate<Boolean> isNull = Objects::isNull;
Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();
-
Supplier 接口
Supplier接口返回一个任意范围的值,和Function接口不同的是这个接口没有任何参数
示例代码如下:
Supplier<Person> personSupplier = Person :: new
personSupplier.get(); //new Person
-
Consumer接口
Consumer接口代表在单个参数上执行的操作
示例代码如下:
Consumer<Person> con = (p) -> System.out.println("Hello,"+p.name);
con.accept(new Person("Lucy",500.0)); //Hello,Lucy
-
Comparator接口
Comparator是以前版本中的经典接口,Java8在此之上添加了多种默认方法
示例代码如下:
Comparator<Person> comparator = (p1,p2) -> p1.name.comparaTo(p2.name);
Person p1 = new Person("小明",100.0);
Person p2 = new Person("小红",100.0);
comparator.compara(p1,p2);
comparator.reversed().compare(p1, p2);
-
Optional接口
Optional不是函数是接口,这个是用来防止NullPointerException异常的辅助类型。
Optional被定义为一个简单的容器,其值可能是null或者不是null。在Java8之前一般某个函数应该返回非空对象但是偶尔会返回null,而在Java8中,不推荐你返回null,而是返回Optional 。
网友评论