Java8特性总结(二)Lambda表达式,函数式接口,方法引用
2017-01-19 09:44
1281 查看
导航
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=referralhttp://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
相关文章推荐
- java8新特性之函数式接口、lambda表达式、接口的默认方法、方法和构造函数的引用
- [java8] lambda表达式、函数式接口和方法引用
- Java8 lambda表达式、函数式接口、方法引用
- java8新特性总结——lambda表达式之方法引用与构造器引用
- Java 8 函数式接口、lambda表达式、方法以及构造器引用
- Java8 新特性之一---------Lambda表达式和函数式接口
- Java8 新特性----函数式接口,以及和Lambda表达式的关系
- Java 8新特性:新语法方法引用和Lambda表达式及全新的Stream API
- java8新特性lambda表达式, 函数式接口以及Steam流和新的日期时间例子代码
- java8新特性(一)之Lambda表达式和函数式接口
- Java8 Lambda表达式 函数式编程 方法引用
- Java8新特性Lambda表达式、函数式接口
- javaSE_8系列博客——Java语言的特性(三)--类和对象(20)--嵌套类(Lambda 表达式--VS--方法引用)
- Java8 函数式接口 , lambda表达式,接口默认方法
- Java 8新特性:新语法方法引用和Lambda表达式及全新的Stream API
- Java 8 新特性:Lambda 表达式之方法引用(Lambda 表达式补充版)
- Java Lambda(语言篇——lambda,方法引用,目标类型,默认方法,函数接口,变量捕获)
- JDK 8.0 新特性——函数式接口和Lambda 表达式
- Java Lambda表达式及方法引用
- Java8特性总结(三)接口方法,注解,日期,Base64