java8简化代码
在java8之前我们是没办法传递函数,只能传递值,而且在java8之前,我们要对某个列表进行排序,你会使用内部类,或者在使用Swing的时候,会大量使用内部类,如:
List<String> names = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
这样代码不但臃肿,而且不利于阅读,在java8中,出现了一种新语法,叫lambda表达式。先来看看使用lambda表达式之后,会变成什么样子?
List<String> names = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu");
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
还可以变的更短,如
Collections.sort(names, (String a, String b) -> b.compareTo(a));
还可以写成,如
Collections.sort(names, (a, b) -> b.compareTo(a));
还可以优化为:
names.sort((a, b) -> b.compareTo(a));
或者
names.sort(Comparator.reverseOrder());
这样的代码是不是变的简洁很多,本来7行代码直接变成了1行代码。这样大大的简化的代码。
函数式接口
什么是函数式接口?
1、如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口
2、如果我们在某个接口上声明了FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口。
3、如果某个接口只有一个抽象方法,但我们并没有给该接口声明FunctionalInterface注解,那么编译器依旧会将该接口看作是函数式接口。
4、如果在该接口上定义了java.lang.Object的public方法,那么不会记为抽象方法。
5、其中默认方式不是抽象的,所有可以有多个默认方法在定义了函数式接口中。
6、函数式接口可以用lambda表达式,方法引用,构造函数引用来创建。
7、必须是接口,如果是枚举,类,那么编译器会报错。
函数式接口的示例如:
@FunctionalInterface
public interface FunctionalInterface01 {
//抽象方法
void test();
//默认方法
default void test01(){
}
//默认方法
default void test02(){
}
//是java.lang.Object的方法
@Override
String toString();
}
如果定义多个抽象方法,那么就会报错 :
如果是Class,也会报错:
为什么有函数式接口?
为了更好的使用lambda表达式,它是lambda的基础。
如何使用?
直接看例子
public class FunctionalClass01 {
public void myTest(FunctionalInterface01 functionalInterface01){
System.out.println(1);
functionalInterface01.test();
System.out.println(2);
}
public static void main(String[] args) {
FunctionalClass01 class01 = new FunctionalClass01();
class01.myTest(new FunctionalInterface01() {
@Override
public void test() {
System.out.println("test");
}
});
}
}
输出结果为:
1
test
2
也可以使用lambda表达式:
public static void main(String[] args) {
FunctionalClass02 class01 = new FunctionalClass02();
class01.myTest(() -> System.out.println("test"));
}
输出的结果跟上面的示例是一样的。
这就是为什么函数式接口只能有一个方法,因为() -> System.out.println("test")表示就是执行FunctionalInterface01接口里的test方法,看示例:
FunctionalInterface01 functionalInterface01 = ()->System.out.println("test");
java8中内置了很多函数式接口,像Comparator
或者Runnable
等,所有可以直接用lambda表达式来使用他们。
lambda表达式
lambda是通过上下文来知道是什么类型,如果光写一个()->{};编译器不知道这个lambda是什么类型。在java中,lambda表达式是对象,不是函数。在java8之后使用了大量的lambda表达式,尤其是stream。
lambda表达式的基本结构:
->左边是参数,->右边是执行体。如(参数)->{body},比如:
1、(param1,param2,param3...)->{body}
2、(type1 arg1,type2 arg2...)->{body}
3、arg1->方法
4、arg1->{body}
5、方法引用
6、构造方法引用
一个lambda有零个或多个参数,参数的类型可以明确声明,也可以根据上下文推断,所有参数都需要在圆括号里头,多个参数之间用短号隔开,空圆括号表示参数为空。当只有一个参数时且类型可以推断出来,圆括号可以省略,lambda表达式的主体可以是一条或多条语句,如果lambda表达式主体只有一条语句,那么{}可以省略,主体代码的返回值需要和返回类型一致。如果lambda主体有多条语句,那么必须要用{},形成代码块。
方法引用
是特殊的lambda表达式。
1、类名::静态方法名
public static String myString(String str){
System.out.println(str);
return str;
}
public static void main(String[] args) {
List<String> nameList = Arrays.asList("zhangsan","lisi");
nameList.forEach(ConstructorReferences::myString);
}
2、引用名(对象名)::实例方法名
public String myString(String str){
System.out.println(str);
return str;
}
public static void main(String[] args) {
ConstructorReferences1 constructorReferences1 = new ConstructorReferences1();
List<String> nameList = Arrays.asList("zhangsan","lisi");
nameList.forEach(constructorReferences1::myString);
}
3、类名::实例方法名
public class ConstructorReferences2 {
private String name;
private int age;
public ConstructorReferences2(String name, int age) {
this.name = name;
this.age = age;
}
public int compareByAge(ConstructorReferences2 constructorReferences2){
return this.age-constructorReferences2.age;
}
public static void main(String[] args) {
ConstructorReferences2 constructorReferences1 = new ConstructorReferences2("zhangsan",20);
ConstructorReferences2 constructorReferences2 = new ConstructorReferences2("lisi",22);
List<ConstructorReferences2> nameList = Arrays.asList(constructorReferences1,constructorReferences2);
nameList.sort(ConstructorReferences2::compareByAge);
}
get/set方法
}
构造方法引用
语法:类名::new
如:
public String getString(Supplier<String> supplier){
return supplier.get()+"test";
}
public static void main(String[] args) {
MethodReferences4 methodReferences4 = new MethodReferences4();
System.out.println(methodReferences4.getString(String::new));
}
局部变量
@FunctionalInterface
public interface Converter<F, T> {
T convert(F from);
}
final int num = 1;
Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + num);
System.out.println(stringConverter.convert(2)); // 3
下面的写法编译失败:
变量必须设置为final,才可以。
静态变量
与局部变量相反,我们可以从lambda表达式中读写实例字段和静态变量。如:
public class StaticVariables {
static int outerStaticNum;
int outerNum;
void testScopes() {
Converter<Integer, String> stringConverter1 = (from) -> {
outerNum = 23;
return String.valueOf(from);
};
Converter<Integer, String> stringConverter2 = (from) -> {
outerStaticNum = 72;
return String.valueOf(from);
};
}
}
源码地址
查看lambdaexpressions
和functionalinterface
包下的类。
注意:本文归作者所有,未经作者允许,不得转载