Java8特性总结(二)Lambda表达式,函数式接口,方法引用

时间:2023-01-14 18:59:11

导航

Java8特性总结(一)概述
Java8特性总结(二)Lambda表达式,函数式接口,方法引用
Java8特性总结(三)接口方法,注解,日期,Base64

前言

这三个新特性使用的时候关系就很紧密,所有打算用这篇文章详细介绍一下。
特别是Lambda表达式和函数式接口,简直就是密不可分。

Lambda表达式

Lambda表达式的特点就是简介优雅(省代码)。
Lambda表达式很多语言都支持,Java程序员一直在要求Java也要加入这个功能,终于Java8提供了这个功能,使Java8成为继Java5后,变更最大的版本。

Lambda百度百科定义

“Lambda 表达式”
(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。
目前主流语言都支持Lambda:Java,C#,C++,Python,JavaScript等。

闭包百度百科定义

闭包(closure)是指可以包含*(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。
“闭包” 一词来源于以下两者的结合:要执行的代码块(由于*变量被包含在代码块中,这些*变量以及它们引用的对象没有被释放)和为*变量提供绑定的计算环境(作用域)。
在PHP、Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby、Python、Go、Lua、objective c、swift 以及Java(Java8及以上)等语言中都能找到对闭包不同程度的支持。

来一个开胃菜

Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );

请注意参数e的类型是由编译器推测出来的。同时,你也可以通过把参数类型与参数包括在括号中的形式直接给出参数的类型:
forEach的定义

interface Iterable<T> 
{
default void forEach(Consumer<? super T> action)
{
for (T t : this)
{
action.accept(t);
}
}
}
e -> System.out.println( e ) 

的等价代码如下

new Consumer<String>()
{
void accept(String t)
{
System.out.println( e );
}
}

因为forEach的参数是Consumer,而Consumer又是函数接口,因此可以直接用Lambda进行表示。

这样写也可以

Arrays.asList( "a", "b", "d" ).forEach( (String e) -> System.out.println( e ) );

这样写也可以

Arrays.asList( "a", "b", "d" ).forEach( (String e) -> {
System.out.println( e );
});

后一种情况一般是代码较多的时候使用。

lambda表达式是可以访问局部变量的,这样局部变量就变成fianl了,不可以进行修改的。

下面两段代码是一个意思。

String sp="-";
Arrays.asList( "a", "b", "d" ).forEach( (e) ->System.out.println( e+sp ));

final String sp="-";
Arrays.asList( "a", "b", "d" ).forEach( (e) ->System.out.println( e+sp ));

可以读写静态变量和属性。

class LambdaTest 
{
static int staticNum;
int num;

void testScopes()
{
Function<Integer, String> testFunc= (from) -> {
num= 2;
staticnum=1;
return String.valueOf(staticNum+num+from);
};
}
}

函数式接口

到这里有人可能会问Lambda表达式如果有返回值怎么办?
好问题,因为Java8增加了很多函数式接口(在java.util.function包下的接口)

这里的函数式接口可以理解成,定义了很多不同的参数个数待实现接口。

接口 方法 参数 返回值
Function R apply(T t) 一个参数 R
DoubleFunction R apply(double value) 一个参数 R
IntFunction R apply(int value) 一个参数 R
UnaryOperator extends Function T apply(T t) 一个参数 T

接口 方法 参数 返回值
BiFunction R apply(T t, U u) 两个参数 R
BinaryOperator extends BiFunction T apply(T t, T u) 两个参数 T
DoubleBinaryOperator double applyAsDouble(double l, double r) 两个参数 double
DoubleBinaryOperator double applyAsDouble(double l, double r) 两个参数 double
DoubleUnaryOperator double applyAsDouble(double operand) 一个参数 double
IntBinaryOperator int applyAsInt(int left, int right) 两个参数 int
LongBinaryOperator long applyAsLong(long left, long right) 两个参数 long

接口 方法 参数 返回值
DoubleToIntFunction int applyAsInt(double value) 一个参数 int
IntToLongFunction long applyAsLong(int value) 一个参数 long
DoubleToLongFunction long applyAsLong(double value) 一个参数 long
IntToDoubleFunction double applyAsDouble(int value) 一个参数 double

接口 方法 参数 返回值
Predicate boolean test(T t) 一个参数 boolean
BiPredicate boolean test(T t, U u) 两个参数 boolean
DoublePredicate boolean test(double value) 一个参数 boolean
IntPredicate boolean test(int value) 一个参数 boolean

接口 方法 参数 返回值
Supplier T get() T
BooleanSupplier boolean getAsBoolean() boolean
DoubleSupplier double getAsDouble() boolean
IntSupplier int getAsInt() boolean

接口 方法 参数 返回值
Consumer void accept(T t) 一个参数 void
BiConsumer void accept(T t, U u) 两个参数 void
DoubleConsumer void accept(double value) 一个参数 void
IntConsumer void accept(int value) 一个参数 void
ObjDoubleConsumer void accept(T t, double value) 两参数 void

以上的列表是java.util.function包下面的部分函数式接口没有列全,大致可以分为以下几类。

Function<T, R>
BiFunction<T, U, R>
Predicate<T>
Supplier<T>
Consumer<T>

其他的都是Java自己实现的一些特例情况。

其他包下的

Runnable
Comparator
Callable

接下来对每个函数接口进行举例说明

Function

Function<T, R>
{
R apply(T t);
}

这个很好理解就是输入一个类型的参数,经过变换返回另外一个类型的对象。

代码示例:

Function<String, Integer> toInteger = Integer::valueOf;//方法引用
Function<String, String> backToString =toInteger.andThen(String::valueOf);//方法引用
backToString.apply("123"); // "123"

BiFunction

BiFunction<T, U, R>
{
R apply(T t, U u)
}

输入两个不同类型的参数,然后输出第三种类型的对象。

Predicate断言

Predicate<T>
{
boolean test(T t);
}

输入一个类型的参数,经过运算后输出一个boolean值。

代码示例:

Predicate<String> predicate = (s) -> s.length() > 0;
predicate.test("foo"); // true
predicate.negate().test("foo"); // false
Predicate<Boolean> nonNull = Objects::nonNull;
Predicate<Boolean> isNull = Objects::isNull;
Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();

Supplier提供者

Supplier<T>
{
T get();
}

这个用法一般是和默认的构造器进行绑定。
如:

Supplier<String> strSupplier=String::new;
String str=strSupplier.get();

每次get都会调用new String();

Consumer消费者

Consumer<T>
{
void accept(T t);
}

示例代码:

String str="Joy";
Consumer<String> consumer = (p) -> System.out.println("Hello, " + p);
consumer.accept(str);//消费一个String

Runnable

Runnable
{
public abstract void run()
}

这个实现和以前基本没有什么变化。

第一种形式

Runnable r=()->System.out.println();
new Thread(r).start();

最简单形式

new Thread(()->System.out.println()).start();

Comparator比较器

Comparator<T>
{
int compare(T o1, T o2);
}

实现比较方法,主要为排序使用的。

代码例子:

List<String> list=Arrays.asList("tom","bob","joy","joy");
list.sort((a,b)->a.compareTo(b));

怎么又没看见Comparator??
sort()函数

default void sort(Comparator<? super E> c) 

Callable

Callable<V>
{
V call() throws Exception;
}

执行一个操作,同时返回Callable声明的类型。

代码例子:

ExecutorService service=Executors.newFixedThreadPool(10);
Future<String> f=service.submit(()->"hello world");

方法引用

接下来说一下方法引用。
方法引用的例子我们在前面的代码已经使用了。
上面的例子:

Function<String, Integer> toInteger = Integer::valueOf;//方法引用
Function<String, String> backToString = toInteger.andThen(String::valueOf);//方法引用
backToString.apply("123"); // "123"

定义一个接口函数,与一个方法进行关联。
要求就是,参数返回值必须要保证一致。
例如上面的
Function<String,Integer> 方法的参数是String,返回值是Integer
Integer.valueOf 这个方法的参数是String,返回值是Integer
这样就可以关联了。

部分参考:

http://www.cnblogs.com/BigFeng/p/5204899.html?utm_source=tuicool&utm_medium=referral
http://baike.baidu.com/item/Lambda%E8%A1%A8%E8%BE%BE%E5%BC%8F
http://baike.baidu.com/item/%E9%97%AD%E5%8C%85
https://yq.aliyun.com/articles/31514
http://blog.csdn.net/feilengcui008/article/details/45822173