函数式接口和lambda表达式

来源:互联网 发布:java中的类命名规范 编辑:程序博客网 时间:2024/05/29 12:49

函数式接口和lambda表达式

函数式接口(Functional Interface) :

​ 任何接口,如果只包含唯一 一个抽象方法,那么它就是一个FI。(之前它们被称为 SAM类型,即 单抽象方法类型(Single Abstract Method))。接口中的方法默认就是public abstract的。

​ 接口可能继承了一个 Object 已经提供的方法,比如 toString()equals( )…这些都不属于函数式接口方法的范畴, 所以函数式接口中所说的方法不包括这些。例如下面FI接口也是一个函数式接口。

@FunctionalInterfaceInterface FI{   judge(int a);   equals();      }

​ API作者们可以通过 @FunctionalInterface 注解来显式指定一个接口是函数式接口。加上这个注解,接口中函数式接口方法少于一个或者多余一个,编译器都会提示错误。

lambda表达式

lambda表达式是匿名方法 ,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。

// 1. 不需要参数,返回值为 5() -> 5// 2. 接收一个参数(数字类型),返回其2倍的值x -> 2 * x// 3. 接收2个int型整数,返回他们的和(int x, int y) -> x + y// 4. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)(String s) -> { System.out.print(s) }

lambda 表达式的语法由参数列表、箭头符号 -> 和函数体组成。函数体既可以是一个表达式,也可以是一个语句块。

假设我们想对一个List按字符串长度进行排序,那么在Java8之前,可以借助匿名内部类来实现:

List<String> words = Arrays.asList("apple", "banana", "pear");words.sort(new Comparator<String>() {    @Override    public int compare(String w1, String w2) {        return Integer.compare(w1.length(), w2.length());    }});

上面的匿名内部类简直可以用丑陋来形容,唯一的一行逻辑被五行垃圾代码淹没。根据前面的定义(并查看Java源代码)可知,Comparator是个FI,所以,可以用Lambda表达式来实现:

words.sort((String w1, String w2) -> {    return Integer.compare(w1.length(), w2.length());});

代码变短了好多!仔细观察就会发现,Lambda表达式,很像一个匿名的方法,只是圆括号内的参数列表和花括号内的代码被->分隔开了。垃圾代码写的越少,我们就有越多的时间去写真正的逻辑代码,不是吗?是的!圆括号里的参数类型是可以省略的:

words.sort((w1, w2) -> {    return Integer.compare(w1.length(), w2.length());});

如果Lambda表达式的代码块只是return后面跟一个表达式,那么还可以进一步简化:

words.sort(    (w1, w2) -> Integer.compare(w1.length(), w2.length()));

注意,表达式后面是没有分号的!如果只有一个参数,那么包围参数的圆括号可以省略:

words.forEach(word -> {    System.out.println(word);});

如果表达式不需要参数呢?好吧,那也必须有圆括号,例如:

Executors.newSingleThreadExecutor().execute(    () -> {/* do something. */} // Runnable);

怎么用Lambda表达式

​ 既然Lambda表达式这么好用,那么,可以在哪些地方使用呢?如果你真正明白了什么是FI(很容易),应该立刻就能给出答案:任何可以接受一个FI实例的地方,都可以用Lambda表达式。比如,虽然上面给出的例子都是把Lambda表达式当作方法参数传递,可以接受FI作为参数的地方,都可以替换为Lambda表达式。

但实际上你也可以定义变量:

Runnable task = () -> {    // do something};Comparator<String> cmp = (s1, s2) -> {    return Integer.compare(s1.length(), s2.length());};

看两个例子:

使用已有的FI

JDK 1.8 新增加的函数接口:java.util.function 中Predicate 接口是一个函数式接口,它接受一个输入参数 T,返回一个布尔值结果。

eval( )方法的第二个参数是FI, 所以在这里可以用Lambda表达式.

import java.util.Arrays;import java.util.List;import java.util.function.Predicate;public class Java8Tester {   public static void main(String args[]){      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);      System.out.println("输出所有数据:");      // Predicate<Integer> predicate = n -> true      // n 是一个参数传递到 Predicate 接口的 test 方法      // n 如果存在则 test 方法返回 true      // 传递参数 n      eval(list, n->true);      // Predicate<Integer> predicate1 = n -> n%2 == 0      // n 是一个参数传递到 Predicate 接口的 test 方法      // 如果 n%2 为 0 test 方法返回 true      System.out.println("输出所有偶数:");      eval(list, n-> n%2 == 0 );      // Predicate<Integer> predicate2 = n -> n > 3      // n 是一个参数传递到 Predicate 接口的 test 方法      // 如果 n 大于 3 test 方法返回 true      System.out.println("输出大于 3 的所有数字:");      eval(list, n-> n > 3 );   }   public static void eval(List<Integer> list, Predicate<Integer> predicate) {      for(Integer n: list) {         if(predicate.test(n)) {            System.out.print(n + " ");         }      }   }}

输出

输出所有数据:1 2 3 4 5 6 7 8 9 输出所有偶数:2 4 6 8 输出大于 3 的所有数字:4 5 6 7 8 9 

自定义FI

自定义一个FI,里面有一个add( ) 方法。 想不出什么好的例子,随便举个例子很简单能说明问题足矣

package com.java8;/** * Created by susq on 2017-6-20. */@FunctionalInterfacepublic interface Fitest {    int add(int a, int b);}
package com.java8;/** * Created by susq on 2017-6-19. */public class LamJava8 {    public static void main(String[] args) {        int a = 2, b = 3;        int result = addMethod( a, b, (c, d) -> { return c+d; } );        System.out.println( result );    }    public static int addMethod(int a, int b, Fitest fi) {        return fi.add(a, b);    }}

输出:5

方法addMethod(int a, int b, Fitest fi) 第三个参数是我们自定义的FI, 因此这里可以用(c, d) -> { return c+d; }表达式,c, d是Fitest 中 add( ) 方法的两个参数, { return c+d; } 是add 方法的方法体。这里c, d不能写a, b,会提示变量重复定义编译错误。 因为(c, d) 实质为像(int c, int d) 一样的形参, int被我们省略了。

参考:http://www.tuicool.com/articles/beA7V3
http://lucida.me/blog/java-8-lambdas-insideout-language-features/

阅读全文
0 0
原创粉丝点击