栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > .Net

JAVA8新特性之Lambda表达式、函数式接口、方法引用

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JAVA8新特性之Lambda表达式、函数式接口、方法引用

什么是Lambda表达式?

可以把lambda表达式理解为简洁的匿名函数,lambda表达式没有名称,但是又参数列表、函数主体、返回类型、还可能抛出一个异常。

先来感受一下lambda的强大
//遍历list
List list = new ArrayList<>();
Collections.addAll(list,"小黑","小俐","小翔");
list.forEach(item->{ System.out.println(item); });
list.forEach(System.out::println);//简写
//遍历map
Map map = new HashMap<>();
map.put("小翔",210);
map.put("小俐",160);
map.put("小黑",720);
map.forEach((k,v) -> System.out.println( k + " : " + v));
再来一个排序的例子
List list  = new ArrayList<>();
Collections.addAll(list,3,2,1);
//自定义排序规则
list.sort(new Comparator() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1 - o2;
    }
});
//lambda写法
list.sort((Integer o1,Integer o2)-> {
    return o1-o2;
});
//输出结果 1 2 3
list.forEach(System.out::println);
显而易见,使用Lambda表达式以后,代码看起来更清晰更简洁了,以排序的这个例子我们来看一下lambda的组成

参数列表: Integer o1,Integer o2

箭头: ->把参数列表和主体分隔为两个部分

主体: o1-o2

Lambda表达式的基本语法
  1. (参数列表) -> 表达式
  2. (参数列表) -> { 多条语句 }

当主体为一条语句时{}可以省略 ,当主体是一个表达式时return可以省略。

list.sort((Integer o1,Integer o2)->  o1-o2;);

编译器可以通过函数式接口推断出Lambda表达式的参数类型,所以在编写Lambda表达式时,可以省略参数类型。比如:

list.sort((o1, o2)->  o1-o2;);

当参数列表有且只有一个参数时,参数的小括号可以省略

list.forEach(item->System.out.println(item););

无参的时候()不可用省略,以实现Runnable接口为例

Runnable runnable=()-> System.out.println("Runnable 运行");

有小伙伴会发现我们实现Runnable接口的run()方法并没有指定方法名,那lambda是怎么知道实现那个方法呢?别着急接下来我们来看函数式接口。

函数式接口

只包含一个抽象方法的接口,就称为函数式接口。我们可以通过Lambda表达式来创建该接口的实现对象。

我们可以在任意函数式接口上使用@FunctionalInterface注解,这样做可以用于检测它是否是一个函数式接口。

我们来看Runnable接口源码。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

自定义函数式接口

@FunctionalInterface
public interface MyFuncInterf  {
    public T getValue(String origin);
}


public class Test {
    public static void main(String[] args) {
        Integer length = length(new MyFuncInterf() {
            @Override
            public Integer getValue(String origin) {
                return origin.length();
            }
        },"ABC");
       System.out.println(length); //3
       //lambda 
       Integer length2 = length(origin->origin.length(),"ABC");
        System.out.println(length2);//3
    }
    public static Integer length(MyFuncInterf interf,String str){
        Integer length = interf.getValue(str);
        return length;
    }
}
常用的函数式接口

在Java8支持Lambda表达式以后,为了满足Lambda表达式的一些典型使用场景,JDK为我们提供了大量常用的函数式接口。它们主要在 java.util.function 包中,下面简单介绍几个其中的接口及其使用示例。

Supplier:供给型接口

看一下源码

package java.util.function;
@FunctionalInterface
public interface Consumer {
    void accept(T t);
}

public class Student {
    private String name;
    private Integer age;
    public Student() {}
    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public Student(Integer age) {
        this.age = age;
    }
}

下面我们使用Lambda表达式声明一个Supplier的实例:

//实现supplier的get方法并创建supplier的实例:
Supplier supplier = () -> new Student("小黑", 18)
Student student = supplier.get();//调用supplier的get方法
System.out.println("name: " + student.getName() + ", age: " + student.getAge());

Consumer:消费型接口

源码如下

package java.util.function;
@FunctionalInterface
public interface Consumer {
    void accept(T t);
}
public class Test {
    public static void main(String[] args) {
        println(100,num -> System.out.println(num));
    }
    public static void println(Integer money, Consumer consumer){
        consumer.accept(money);
    }
}

Predicate:断言型接口

public static void main(String[] args) {
    List list = new ArrayList<>();
    Collections.addAll(list,1,2,3,4,5);
    List list1 = filterNum(list, (x) -> x < 3);
    list1.forEach(x-> System.out.println(x));
}

public static  List filterNum(List list, Predicate predicate){
    ArrayList resultList = new ArrayList();
    for (Integer item : list) {
        if (predicate.test(item)){
            resultList.add(item);
        }
    }
    return resultList;
}

Function: 函数式接口

public static void main(String[] args) {
    System.out.println(changeNum(1,(x) -> x+1));
}

public static Integer changeNum(Integer num, Function fun){
    return fun.apply(num);
}
方法引用 什么是方法引用?

方法引用是Java8中引入的新特性,它提供了一种引用方法而不执行方法的方式,当要传递给Lambda体的操作,已经有实现的方法了,就可以使用方法引用!(实现抽象方法的参数列表,必须与方法引用的参数列表一致,方法的返回值也必须一致,即方法的签名一致)。方法引用可以理解为方法引用是Lambda表达式的另外一种表现形式。
方法引用的语法:使用操作符 :: 将对象或类和方法名分隔开。

eg:

list.forEach(System.out::println);

对象:实例方法名

PrintStream out = System.out;
Consumer consumer = out::println;
consumer.accept("hello");

类::静态方法名

静态方法引用使用 类名::方法名

Comparator comparable=(x,y)->Integer.compare(x,y);
//使用方法引用实现相同效果
Comparator integerComparable = Integer::compare;
System.out.println(integerComparable.compare(4,2));//结果:1
System.out.println(comparable.compare(4,2));//结果:1

类::实例方法名

实例方法引用使用 实例名::方法名

BiPredicate bp=(x,y)->x.equals(y);
//使用方法引用实现相同效果
String str = new String();
BiPredicate bp2 = string::equals;
System.out.println(bp.test("1","2"));//结果:false
System.out.println(bp.test("1","2"));//结果:false
构造器引用

格式:类名::new

自动与函数式接口中方法兼容,可以把构造器引用赋值给定义的方法。需要注意构造器参数列表要与接口中抽象方法的参数列表一致。使用示例:

public class Student {
    private String name;
    private Integer age;
    public Student() {}
    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public Student(Integer age) {
        this.age = age;
    }
}
//引用无参构造器
Supplier supplier= Student::new;
System.out.println(supplier.get());
//引用有参构造器
Function function = Student::new;
System.out.println(function.apply(21));
//引用全参构造器
BiFunction biFunction = Student::new;
System.out.println(biFunction.apply("小黑",21));
数组引用
Function function = String[]::new;
String[] apply = function.apply(10);
System.out.println(apply.length);//结果:10
转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1023927.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号