您的位置:首页 > 编程语言 > Java开发

java8.Lambda表达式

2016-03-02 09:39 429 查看
转载自:http://www.jb51.net/article/48304.htm
http://www.oschina.net/translate/everything-about-java-8

Lambda表达式

使用Java8之前的语法,如何实现比较器:

[java] view
plain copy

List<Integer> list = Arrays.asList(7, 4, 1, 2);

Collections.sort(list, new Comparator<Integer>() {

@Override

public int compare(Integer a, Integer b) {

return a > b ? 1 : (a == b) ? 0 : -1;

}

});

System.out.println(list);// [1, 2, 4, 7]

在Java 8 中就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式:

[java] view
plain copy

Collections.sort(list, (Integer a, Integer b) -> {

return a > b ? 1 : (a == b) ? 0 : -1;

});

代码变得更段且更具有可读性,但是实际上还可以写得更短:

[java] view
plain copy

Collections.sort(list, (Integer a, Integer b) -> a > b ? 1 : (a == b) ? 0 : -1);

对于函数体只有一行代码的,可以去掉大括号{}以及return关键字,但是还可以写得更短点:

[java] view
plain copy

Collections.sort(list, (a, b) -> a > b ? 1 : (a == b) ? 0 : -1);

Java编译器可以自动推导出参数类型,所以可以不用再写一次类型。

当把经典风格java语法转变为Lambda表达式语法时,主要关注接口方法的参数和功能逻辑。

另外一个例子,如果打算写一个方法,此方法接收一个Lambda表达式作为参数,那么该怎么写?首先把方法参数声明成函数接口,然后才能传递Lambda表达式进来,如下所示:

[java] view
plain copy

interface Action {

void doThing(String param);

}

[java] view
plain copy

public void func(Action actor) {

actor.doThing("Hello World!");

}

如果想要调用func()方法,那么通常地做法,给func方法传递一个Action的匿名实现类。如下所示:

[java] view
plain copy

new LambdaTest().func(new Action() {

@Override

public void doThing(String param) {

System.out.println("Hi! " + param);

}

});

但是现在有函数接口做参数类型,所以可以用下面的方式调用func ():

[java] view
plain copy

new LambdaTest().func((String parm) -> {

System.out.println("Hi! " + parm);

});

甚至可以更简单:

[java] view
plain copy

new LambdaTest().func(parm -> System.out.println("Hi! " + parm));

接口的默认方法(default)

Java 8允许给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下:

[java] view
plain copy

public class Test {

public static void main(String[] args) {

Formula formula = new Formula() {

@Override

public double calculate(int a) {

return sqrt(a * 100);

}

};

System.out.println(formula.calculate(100)); // 100.0

System.out.println(formula.sqrt(16)); // 4.0

}

}

interface Formula {

double calculate(int a);

default double sqrt(int a) {

return Math.sqrt(a);

}

}

函数式接口

Lambda表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。而“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为默认方法不算抽象方法,所以也可以给你的函数式接口添加默认方法。

可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保接口一定达到这个要求,只需要给接口添加 @FunctionalInterface 注解,编译器如果发现标注了这个注解的接口有多于一个抽象方法的时候会报错的。

[java] view
plain copy

@FunctionalInterface

interface Converter<F, T> {

T convert(F from);

}

[java] view
plain copy

Converter<String, Integer> converter = (aa) -> Integer.valueOf(aa);

Integer converted = converter.convert("123");

System.out.println(converted); // 123

需要注意如果@FunctionalInterface如果没有指定,上面的代码也是对的。

JDK8中新增了一个包,java.util.function,这个包里有一些专门给新增的API使用的函数接口。

下面列出几个java.util.function中定义的接口:

[java] view
plain copy

public interface Consumer<T> : void accept(T t);//在T上执行一个操作,无返回结果

public interface Supplier<T> : T get();//无输入参数,返回T的实例

public interface Predicate<T> : boolean test(T t);// 输入参数为T的实例,返回boolean值

public interface Function<T, R> : R apply(T t);// 输入参数为T的实例,返回R的实例

方法引用:

静态方法引用: String::valueOf

非静态方法引用: Object::toString

继承的函数引用: x::toString

构造函数引用: ArrayList::new

方法引用 等价的lambda表达式

String::valueOf x -> String.valueOf(x)

Object::toString x -> x.toString()

x::toString () -> x.toString()

ArrayList::new () -> new ArrayList<>()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: