一, 函数式编程
java中的函数式编程体现就是Lambda和方法引用:
Lambda
// 1.1使用匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello world !");
}
}).start();
// 1.2使用 lambda 获得Runnable接口对象
new Thread(() -> System.out.println("Hello world !")).start();
Lambda除了简洁之外,还具有延迟执行特点
延迟执行
有些场景的代码执行后,结果不一定会被使用,从而造成性能浪费。而Lambda表达式是延迟执行的,这正好可以作为解决方案,提升性能。
public class Demo01Logger {
private static void log(int level, String msg) {
if (level == 1) {
System.out.println(msg);
}
}
public static void main(String[] args) {
String msgA = "Hello";
String msgB = "World";
String msgC = "Java";
log(2, msgA + msgB + msgC);//级别1 不一定能够满足 但是 字符串连接操作还是执行了 那么字符串的拼接操作就白做了,存在性能浪费
}
}
Lambda的更优写法:
@FunctionalInterface
public interface MessageBuilder {
String buildMessage();
}
public class Demo02LoggerLambda {
private static void log(int level, MessageBuilder builder) {
if (level == 1) {
System.out.println(builder.buildMessage());// 实际上利用内部类 延迟的原理,代码不相关 无需进入到启动代理执行
}
}
public static void main(String[] args) {
String msgA = "Hello";
String msgB = "World";
String msgC = "Java";
log(2,()->{
System.out.println("lambda 是否执行了");
return msgA + msgB + msgC;
});
}
}
方法引用
方法引用,不是方法调用!
方法引用是 lambda 表达式的语法糖,任何用方法引用的地方都可由lambda表达式替换
list.forEach(value -> System.out.println(value));
可替换为
list.forEach(System.out::println);
类别 | 使用形式 |
---|---|
静态方法引用 | 类名 :: 静态方法名 |
实例方法引用 | 对象名(引用名) :: 实例方法名 |
类方法引用 | 类名 :: 实例方法名 |
构造方法引用 | 类名 :: new |
二, 函数式接口
定义:函数式接口(Functional Interface):有且仅有一个抽象方法的接口,但可以有多个非抽象方法的接口
- 你可以通过 Lambda 表达式或方法引用来创建该接口的对象。
- 可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检测它是否是一个函数式接口
@FunctionalInterface
在JDK 8中引入了FunctionalInterface接口,其源代码定义如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
加上@FunctionalInterface标注,则会触发JavaCompiler的检查。对于符合函数接口的接口,加不加都无关紧要,但是加上则会提供一层编译检查的保障。如果不符合,则会报错。
需要注意的是:接口中只能存在一个抽象方法
格式:
修饰符 interface 接口名称{
public abstract 返回值 方法名称(参数列表)
// 其他方式
}
// public abstract 可以不写 编译器自动加上
修饰符 interface 接口名称{
返回值 方法名称(参数列表)
// 其他方式
}
调用举例:
@FunctionalInterface // 标明为函数式接口
public abstract MyFunctionInterface{
void method(); //抽象方法
}
public class TestFunctional {
// 定义一个含有函数式接口的方法
public static void doSomething(MyFunctionInterface functionalInterface) {
functionalInterface.method();//调用自定义函数式接口的方法
}
public static void main(String[] args) {
//调用函数式接口的方法
MyFunctionInterface functionalInterface = () -> System.out.println("hello!")
doSomething(functionalInterface );
}
}
常用函数式接口
接口 | 参数 | 返回值 | 说明 |
---|---|---|---|
Supplier |
无 | T | 供给型;无参,返回一个指定泛型的对象 |
Consumer |
T | 无 | 消费型;传入一个指定泛型的参数,无返回值 |
Predicate |
T | Boolean | 断言型;判断函数,返回判断结果true/false |
Function |
T | R | 方法型;输入一个参数,得到一个结果 |
Supplier
无参有返回值
@FunctionalInterface
public interface Supplier {
T get();
}
使用:
public class TestSupplier {
public static void main(String[] args) {
// 产生的数据作为 sout 作为输出
Supplier supply = ()->"产生数据"
System.out.println(supply.get());//输出“产生数据”
}
}
Consumer
有参无返回值
@FunctionalInterface
public interface Consumer {
void accept(T t);
...
}
使用:
public class TestComsumer {
public static void main(String[] args) {
Consumer consumer = s->System.out.println(s)
consumer.accept("hello");//输出“hello”
}
}
Predicate
对入参数据进行判断,并返回boolean
@FunctionalInterface
public interface Predicate {
boolean test(T t);
...
}
使用:
public class UsePredicate {
public static void main(String[] args) {
Predicate predicate = (x)-> x==10;
System.out.println(predicate.test(10));//输出true
}
}
Function
将入参T转为返回值R
@FunctionalInterface
public interface Function {
R apply(T t);
}
使用:
// 将数字转换为String类型
private static void numberToString() {
String apply = function.apply(12);
System.out.println("转换结果:"+apply);
}
public static void main(String[] args) {
Function function = (s)->String.valueOf(s)
System.out.println("转换结果:"+function.apply(12));//输出“12”
}
三, Functional Java
Functional Java是一个第三方库,是一个在Java语言中实现函数型编程范式的类库。
标准的Java 8 也引入了很多函数型编程范式的元素,比如Stream,lambda以及函数型接口。但在功能上Java 8 远不如Functional Java丰富,使用上也受到一定的限制。
Functional 项目地址:https://github.com/functionaljava/functionaljava
引入
//主包
compile "org.functionaljava:functionaljava:4.8"
//可以不引入
compile "org.functionaljava:functionaljava-java8:4.8"
compile "org.functionaljava:functionaljava-quickcheck:4.8"
compile "org.functionaljava:functionaljava-java-core:4.8"
F0, F, F2, …, F8
对应Fuction
F0没有入参,F有1个入参,…,F8有8个入参
返回值类型都只有一个,最后那个类型参数代表返回值类型。
F twice = n -> n * 2;
F2 f = (a, b) -> a + b;
F3 g = (a, b, c) -> a + b + c;
Effect0, Effect1, Effect2, …, Effect8
没有返回值的函数接口类型, 对应Consumer
Effect0没有入参,Effect1有1个入参,…,Effect8有8个入参
Effect1 abc = n -> System.out.println(n);
FJ 接口 | FJ 方法 | Java 8 接口 | Java 8 方法 |
---|---|---|---|
Effect2 |
f | BiConsumer |
accept |
F2 |
f | BiFunction |
apply |
F2 |
f | BinaryOperator |
apply |
F2 |
f | BiPredicate |
test |
F0 |
f | BooleanSupplier | getAsBoolean |
其他特性不多做介绍了。。。