函数式接口及Lamada表达式
随着jdk1.8使用的越来越广泛,函数式接口和Lamada表达式作为其中的2个重要新特性,学习并掌握它已经成为必备。如果你有看过一些开源项目的源码就会发现函数式接口和Lamada表达式几乎都有使用。
一、jdk1.8接口的3个新特性
1、default关键字,这里的default是用于修饰方法的(jdk1.8新特性),而且只能在interface接口里修饰方法,被修饰的方法必须包含方法体。
2、static关键字,jdk1.8允许在接口里修饰方法,被static修饰的方法必须包含报文体。
3、注解@FunctionalInterface
用于表示当前接口类为函数式接口,而且这个函数式接口必须有且只能有一个待实现的方法,而default、static修饰的方法不算待实现的方法。
用代码展示如下:
public interface User { 传统的接口类,全部都是未实现的方 |
public interface User { 全部都是已实现的方法,但是不是函数式接口,因为函数式接口要有一个未实现的方法 |
public interface User { 虽然没有用@ FunctionalInterface注解修饰类,但是也是符合函数式接口的条件:有且只有一个未实现的方法。 |
@FunctionalInterface public interface User { 标准的函数式接口。 |
二、jdk1.8新增的函数式接口
Jdk1.8新增了一个函数式接口的包:java.util.function,里面包含了下面这么多接口:
BiConsumer
BiPredicate
BooleanSupplier
Consumer
DoubleConsumer
DoubleFunction
DoublePredicate
DoubleSupplier
DoubleToIntFunction
DoubleToLongFunction
DoubleUnaryOperator
IntConsumer
IntPredicate
IntSupplier
LongConsumer
LongFunction
LongPredicate
LongSupplier
LongToDoubleFunction
LongToIntFunction
LongUnaryOperator
ObjDoubleConsumer
ObjIntConsumer
ObjLongConsumer
Predicate
Supplier
ToDoubleBiFunction
ToDoubleFunction
ToIntBiFunction
ToIntFunction
ToLongBiFunction
ToLongFunction
UnaryOperator
IntUnaryOperator
IntToDoubleFunction
IntFunction
IntToLongFunction
LongBinaryOperator
IntBinaryOperator
DoubleBinaryOperator
BiFunction
BinaryOperator
Function
归纳总结一下,就是下面几类:
Java.util.function包下的函数式接口类型 |
说明 |
Consumer类 |
有参数,无返回值 |
Function类 |
有参数,有返回值 |
Predicate类 |
有参数,返回boolean值 |
Supplier类 |
无参数,有返回值 |
Consumer类源码
public interface Consumer<< span="">T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
/**
* Returns a composed {@code Consumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code Consumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
Function类
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
/**
* Returns a composed function that first applies the {@code before}
* function to its input, and then applies this function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of input to the {@code before} function, and to the
* composed function
* @param before the function to apply before this function is applied
* @return a composed function that first applies the {@code before}
* function and then applies this function
* @throws NullPointerException if before is null
*
* @see #andThen(Function)
*/
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
/**
* Returns a composed function that first applies this function to
* its input, and then applies the {@code after} function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of output of the {@code after} function, and of the
* composed function
* @param after the function to apply after this function is applied
* @return a composed function that first applies this function and then
* applies the {@code after} function
* @throws NullPointerException if after is null
*
* @see #compose(Function)
*/
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
/**
* Returns a function that always returns its input argument.
*
* @param << span="">T> the type of the input and output objects to the function
* @return a function that always returns its input argument
*/
static <T> Function<T, T> identity() {
return t -> t;
}
}
Predicate类
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
/**
* Returns a composed predicate that represents a short-circuiting logical
* AND of this predicate and another. When evaluating the composed
* predicate, if this predicate is {@code false}, then the {@code other}
* predicate is not evaluated.
*Any exceptions thrown during evaluation of either predicate are relayed *
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ANDed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* AND of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
/**
* Returns a predicate that represents the logical negation of this
* predicate.
*
* @return a predicate that represents the logical negation of this
* predicate
*/
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);
}
}
Supplier类
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
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);
}
}
三、Jdk1.8以前旧接口中的函数式接口
Runnable
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface Runnable is used
* to create a thread, starting the thread causes the object's
* run method to be called in that separately executing
* thread.
*
public abstract void run();
}
Java.io.FileFilter
@FunctionalInterface
public interface FileFilter {
/**
* Tests whether or not the specified abstract pathname should be
* included in a pathname list.
*
* @param pathname The abstract pathname to be tested
* @return true if and only if pathname
* should be included
*/
boolean accept(File pathname);
}
Java.io.FilenameFilter
@FunctionalInterface
public interface FilenameFilter {
/**
* Tests if a specified file should be included in a file list.
*
* @param dir the directory in which the file was found.
* @param name the name of the file.
* @return true if and only if the name should be
* included in the file list; false otherwise.
*/
boolean accept(File dir, String name);
}
四、Lamada表达式
语法:
(参数1,参数2,…) -> {代码块}
意义:
实现函数式接口中未实现的方法。
4.1无参用法
@FunctionalInterface
public interface User {
public String getName();
public default int getAge(){
return 1;
};
static void print(){} ;
}
public class LamadaTest {
@Test
public void testLamada(){
User user = ()->{return "zhang";};
System.out.println(user.getName());
}
}
到这里可以能有人会有疑惑,“()->{return "zhang";}”这段代码怎么就知道是实现User类的getName方法,其实是倒着推导的,因为用的是User类取接收的,而且User类符合函数式接口条件只有一个未实现的方法,所以这里就知道是实现User接口的getName方法。
如果通过方法的参数传一个泛型接口类,那也是通过方法参数的类型来倒推实现的是哪个类的什么方法,代码如下:
public class LamadaTest {
@Test
public void testLamada(){
printUser(()->{return "zhang";});
}
void printUser(User user){
System.out.println(user.getName());
}
}
有参用法
@FunctionalInterface
public interface User {
public void printName(String name);
}
public class LamadaTest {
@Test
public void testLamada(){
printUser((String t)->{System.out.println(t);});
}
void printUser(User user){
user.printName("zhang");
}
}
可以看出Lamada表达式实现接口方法时和User接口定义printName方法时的形参不一致,这里形参不一致是可以的。
如果实现的方法里只有一行语句,如代码中的System.out.println(t),那这个大括号是可以去掉,如下所示:
public void testLamada(){
printUser((String t)->System.out.println(t));
}
如果方法体只有一句,且方法的参数跟方法体里面语句的参数一致,还可以用方法引用的方式来写,方法引用通过“::”来实现。IDEA工具会提示Lamada的简写方式(对可以简写的语句标黄),把光标放在这段代码中按“alt+enter”键会自动转换成简写方式。
public void testLamada(){
printUser(System.out::println);
}
精选推荐:
*本文为IT技术栈原创文章,独家版权归于本平台,受到原创保护。任何渠道的转载请后台留言联系授权,侵权必究。