【Java8实战】Lambda表达式(二)

在上一节中,我们为了使用Lambda表达式不得不创建了各种函数描述符的函数式接口,其实Java 8已经给我们提供了一套能够描述常见函数描述符的函数式接口。比如Predicate<T>、Consumer<T>、Function<T,R>、Supplier<T>等,这些函数式接口位于java.util.function包。这一节主要记录这些函数式接口的应用。

Java8中的函数式接口

下表列出了Java8中常见的函数式接口:

函数式接口 函数描述符 原始类型特化
Predicate T->boolean IntPredicate,LongPredicate, DoublePredicate
Consumer T->void IntConsumer,LongConsumer, DoubleConsumer
Function<T,R> T->R IntFunction, IntToDoubleFunction, IntToLongFunction, LongFunction, LongToDoubleFunction, LongToIntFunction, DoubleFunction, ToIntFunction, ToDoubleFunction, ToLongFunction
Supplier ()->T BooleanSupplier,IntSupplier, LongSupplier, DoubleSupplier
UnaryOperator T->T IntUnaryOperator, LongUnaryOperator, DoubleUnaryOperator
BinaryOperator (T,T)->T IntBinaryOperator, LongBinaryOperator, DoubleBinaryOperator
BiPredicate<L,R> (L,R)->boolean  
BiConsumer<T,U> (T,U)->void ObjIntConsumer, ObjLongConsumer, ObjDoubleConsumer
BiFunction<T,U,R> (T,U)->R ToIntBiFunction<T,U>, ToLongBiFunction<T,U>, ToDoubleBiFunction<T,U>

Predicate

predicate: 英 [?pred?k?t] 美 [?pred?k?t] 断言,断定的意思。从接口的名称就可以推断出这个函数式接口的主要作用就是用于判断作用,Predicate源码如下所示:

@FunctionalInterfacepublic interface Predicate<T> {    boolean test(T t);?    default Predicate<T> and(Predicate<? super T> other) {        Objects.requireNonNull(other);        return (t) -> test(t) && other.test(t);    }    default Predicate<T> negate() {        return (t) -> !test(t);    }    default Predicate<T> or(Predicate<? super T> other) {        Objects.requireNonNull(other);        return (t) -> test(t) || other.test(t);    }    static <T> Predicate<T> isEqual(Object targetRef) {        return (null == targetRef)                ? Objects::isNull                : object -> targetRef.equals(object);    }}

可看到java.util.function.Predicate<T>接口定义了一个名叫test的抽象方法,它接受泛型T对象,并返回一个boolean,函数描述符为(T) -> boolean举几个例子:

// 偶数判断Predicate<Integer> isEven = (in) -> in % 2 == 0;isEven.test(17); // false?// 判断字符串的长度是否为0Predicate<String> isEmptyString = String::isEmpty;isEmptyString.test(""); // true

除了抽象方法外,java.util.function.Predicate<T>接口还定义了三个默认方法:and,negate和or,对应“与”,“非”和“或”操作,这样我们便可以复合Lambda表达式了,比如:

// 判断是偶数,并且大于30Predicate<Integer> isEven = (in) -> in % 2 == 0;isEven.and((in) -> in > 30).test(40); // true?// 奇数判断Predicate<Integer> isEven = (in) -> in % 2 == 0;Predicate<Integer> isOdd = isEven.negate();isOdd.test(17); // true

Consumer

英 [k?n?sju:m?(r)] 美 [k?n?su:m?(r)] n.消费者。该函数式接口用于消费一个对象,即接收一个对象,对其执行某些操作,然后没有返回值。Consumer源码如下所示:

@FunctionalInterfacepublic interface Consumer<T> {    void accept(T t);    default Consumer<T> andThen(Consumer<? super T> after) {        Objects.requireNonNull(after);        return (T t) -> { accept(t); after.accept(t); };    }}

可看到java.util.function.Consumer<T>定义了一个名叫accept的抽象方法,它接受泛型T的对象,没有返回(void),函数描述符为(T) -> void。其还提供了一个默认方法andThen。举个例子:

Consumer<Apple> printAppleColor = (a)-> System.out.println(a.getColor());printAppleColor.accept(new Apple("red",17)); // red?printAppleColor.andThen((a) -> System.out.println(a.getWeight())).accept(new Apple("red", 17)); // red 17.0

Supplier

supplier 英 [s??pla??(r)] 美 [s??pla??r] n.供应商;供应者;供给者。其源码如下:

@FunctionalInterfacepublic interface Supplier<T> {    T get();}

可看到java.util.function.Supplier<T>定义了一个名叫get的抽象方法,它不接收参数,返回泛型T的对象,函数描述符为() -> T。举个例子:

Supplier<Person> personSupplier = Person::new;personSupplier.get();   // new Person

Functions

Functions源码如下:

@FunctionalInterfacepublic interface Function<T, R> {    R apply(T t);?    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {        Objects.requireNonNull(before);        return (V v) -> apply(before.apply(v));    }?    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {        Objects.requireNonNull(after);        return (T t) -> after.apply(apply(t));    }?    static <T> Function<T, T> identity() {        return t -> t;    }}

java.util.function.Function<T, R>接口定义了一个叫作apply的方法,它接受一个泛型T的对象,并返回一个泛型R的对象,函数描述符为(T) -> R。举个例子:

Function<Apple, Double> getAppleWeight = (a) -> {    return a.getWeight();};getAppleWeight.apply(new Apple(17)); // 17.0

Functions接口还提供了两个抽象方法compose和andThen,从源码可以看出两者的根本区别。举个compose例子:

Function<Integer, Integer> f = (x) -> x + 1;Function<Integer, Integer> g = (x) -> x * 2;f.compose(g).apply(2); // 5

过程为:f(g(2)),也就是1+(2*2)。

举个andThen的例子:

Function<Integer, Integer> f = (x) -> x + 1;Function<Integer, Integer> g = (x) -> x * 2;f.andThen(g).apply(2); // 6

过程为:g(f(2)),也就是(2+1)*2。

原始类型特化

在学习Function接口的时候,我们定义了f函数:

Function<Integer, Integer> f = (x) -> x + 1;

x的类型为Integer类型,1为int类型,返回值为Integer类型,整个过程实际上为Integer.valueOf(x.intValue() + 1)。虽然编译器可以自动帮我们完成拆装箱,但这会造成不必要的性能消耗。考虑到了这一点,Java8为我们提供了int类型的Function接口:IntFunction:

@FunctionalInterfacepublic interface IntFunction<R> {    R apply(int value);}

所以f最好重构为:

IntFunction<Integer> f = (x) -> x + 1;

剩余的原始类型特化函数式接口可参考上面的表格。

Java8中增强的Comparator

在Java8之前,Comparator接口用于实现简单的比较排序算法。比如有如下List:

List<Double> list = new ArrayList<>();list.add(12.3);list.add(100.2);list.add(3.14);list.add(27.7);list.add(-9.8);

使用Comparator接口对其从小到大排序:

Collections.sort(list, new Comparator<Double>() {    @Override    public int compare(Double o1, Double o2) {        return o1.compareTo(o2);    }});

Comparator接口也是一个函数式接口,函数描述符为(T,T) -> int,Java8中可以使用Lambda改造上面的排序方法:

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

Java8对List提供了sort方法,可以替代Collections.sort,所以上面的代码可以简化为:

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

使用方法的引用来进一步简化:

list.sort(Double::compareTo);

Java8对Comparator进行了增强,加入了一些实用的默认方法,比如对排序结果反转:

Comparator<Double> comparator = Double::compareTo;list.sort(comparator.reversed());

更多方法可以参考Comparator接口的JavaDoc。

查看Comparator的时候发现其虽然是函数式接口,但是却包含了compare和equals这两个抽象方法,顿时有点懵逼,函数式接口不是只能有一个抽象方法么?查找资料后发现:函数式接口中可以额外定义多个抽象方法,但这些抽象方法签名必须和Object的public方法一样,接口最终有确定的类实现,而类的最终父类是Object。因此函数式接口可以定义Object的public方法。

原文地址:https://www.cnblogs.com/7788IT/p/11625513.html

时间: 2024-10-11 17:27:18

【Java8实战】Lambda表达式(二)的相关文章

java8新特性-Lambda表达式(二)

Java8新增了java.util.funcion包,里面包含常用的函数接口,这是Lambda表达式的基础,Java集合框架也新增部分接口,以便与Lambda表达式对接. Collections中的常用函数接口 Java集合框架的接口继承结构: 上图中蓝色标记和橙色标记的接口类,表示在Java8中加入了新的接口方法,由于继承关系,他们相应的子类也会继承这些方法. 下面用一张表列举这些方法 接口名 Java8新加入的方法 Collection removeIf() spliterator() st

JAVA8之lambda表达式详解,及stream中的lambda使用

原文:http://blog.csdn.net/jinzhencs/article/details/50748202 lambda表达式详解 一.问题 1.什么是lambda表达式? 2.lambda表达式用来干什么的? 3.lambda表达式的优缺点? 4.lambda表达式的使用场景? 5.lambda只是一个语法糖吗? 二.概念 lambda表达式是JAVA8中提供的一种新的特性,它支持Java也能进行简单的"函数式编程". 它是一个匿名函数,Lambda表达式基于数学中的λ演算

java8之lambda表达式看这一篇就够了

java8增加了许多新特性,其中lambda表达式可以说为最重要的特性之一,本文将从如下几个方面来学习lambda:     1.lambda表达式的基本定义   2.lambda表达式的语法   3.lambda表达式基本示例 一.何为lambda表达式? 简单点说lambda为一种匿名函数,它既没有名字也没有声明的方法.访问修饰符和返回值等.它允许将函数作为方法的参数进行传递. 二.基本语法:lambda通常包含如下几种书写方式 () -> expression () -> {  stat

公子奇带你一步一步了解Java8中Lambda表达式

在上一篇<公子奇带你一步一步了解Java8中行为参数化>中,我们演示到最后将匿名实现简写为 1 (Police police) -> "浙江".equals(police.getPoliceNativePlace()); 这是一个带有箭头的函数,这种写法在Java8中即为Lambda表达式.那么我们就来好好的讲讲Lambda表达式. 一 .什么是Lambda表达式 首先我们需要知道Lambda表达式时JDK8中提出的编码风格,它可以简洁地表示可作为参数传递的匿名函数的

java8之lambda表达式(方法引用)

有些时候,你想要传递给其他代码的操作已经有实现的方法了.示例: button.setOnAction(event -> System.out.println(event); 如果你能够只将println方法传递给setOnAction方法,就更好了!下面是改后的代码: button.setOnAction(System.out::println); 表达式System.out::println是一个方法引用,等同于lambda表达式: x -> System.out.println(x) 正如

java8之lambda表达式(变量作用域)

通常,我们希望能够在lambda表达式的闭合方法或类中访问其他的变量,例如: package java8test; public class T1 {     public static void main(String[] args) {         repeatMessage("Hello", 20);     }     public static void repeatMessage(String text,int count){         Runnable r = 

java8之lambda表达式(1)-基本语法

参考:http://www.cnblogs.com/andywithu/p/7344507.html lambda表达式,即带有参数的表达式,为更清晰地理解lambda表达式,先看如下例子: (1) class Student{ private String name; private Double score; public Student(String name, Double score) { this.name = name; this.score = score; } public S

java8之lambda表达式入门

1.基本介绍 lambda表达式,即带有参数的表达式,为了更清晰地理解lambda表达式,先上代码: 1.1 两种方式的对比 1.1.1 方式1-匿名内部类 class Student{ private String name; private Double score; public Student(String name, Double score) { this.name = name; this.score = score; } public String getName() { ret

java8之lambda表达式(函数式接口)

在Java中有许多已有的接口都需要封装代码块,例如:Runnable或者Comparator.lambda表达式与这些接口是向后兼容的.对于只包含一个抽象方法的接口,你可以通过lambda表达式来创建该接口的对象,这种接口被称为函数式接口.注意:Java8中接口可以声明非抽象的方法. 为了演示函数式接口转换,我们以Arrays.sort方法为例.该方法的第二个参数需要一个Comparator接口(该接口只含有一个方法)的实例.接下来我们编写一个简单的lambda表达式: Arrays.sort(

Java8的Lambda表达式简介

先阐述一下JSR(Java Specification Requests)规范,即Java语言的规范提案.是向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求.任何人都可以提交JSR,可以向Java平台增添新的API和服务.JSR已成为Java界的一个重要标准.可以理解为JSR是Java开发者以及授权者指定的标准,而Java开发者以及授权者形成一个JCP国际组织.职能是制定Java标准,即所有的规范都是有迹可循的. 在Java8中推出的lambda表达式