一, 函數(shù)式編程
java中的函數(shù)式編程體現(xiàn)就是Lambda和方法引用:
Lambda
// 1.1使用匿名內(nèi)部類
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除了簡潔之外造成,還具有延遲執(zhí)行特點(diǎn)
延遲執(zhí)行
有些場景的代碼執(zhí)行后,結(jié)果不一定會被使用雄嚣,從而造成性能浪費(fèi)晒屎。而Lambda表達(dá)式是延遲執(zhí)行的,這正好可以作為解決方案缓升,提升性能鼓鲁。
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 不一定能夠滿足 但是 字符串連接操作還是執(zhí)行了 那么字符串的拼接操作就白做了,存在性能浪費(fèi)
}
}
Lambda的更優(yōu)寫法:
@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());// 實(shí)際上利用內(nèi)部類 延遲的原理,代碼不相關(guān) 無需進(jìn)入到啟動(dòng)代理執(zhí)行
}
}
public static void main(String[] args) {
String msgA = "Hello";
String msgB = "World";
String msgC = "Java";
log(2,()->{
System.out.println("lambda 是否執(zhí)行了");
return msgA + msgB + msgC;
});
}
}
方法引用
方法引用港谊,不是方法調(diào)用骇吭!
方法引用是 lambda 表達(dá)式的語法糖,任何用方法引用的地方都可由lambda表達(dá)式替換
list.forEach(value -> System.out.println(value));
可替換為
list.forEach(System.out::println);
類別 | 使用形式 |
---|---|
靜態(tài)方法引用 | 類名 :: 靜態(tài)方法名 |
實(shí)例方法引用 | 對象名(引用名) :: 實(shí)例方法名 |
類方法引用 | 類名 :: 實(shí)例方法名 |
構(gòu)造方法引用 | 類名 :: new |
二歧寺, 函數(shù)式接口
定義:函數(shù)式接口(Functional Interface):有且僅有一個(gè)抽象方法的接口燥狰,但可以有多個(gè)非抽象方法的接口
- 你可以通過 Lambda 表達(dá)式或方法引用來創(chuàng)建該接口的對象。
- 可以在任意函數(shù)式接口上使用 @FunctionalInterface 注解斜筐,這樣做可以檢測它是否是一個(gè)函數(shù)式接口
@FunctionalInterface
在JDK 8中引入了FunctionalInterface接口龙致,其源代碼定義如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
加上@FunctionalInterface標(biāo)注,則會觸發(fā)JavaCompiler的檢查。對于符合函數(shù)接口的接口顷链,加不加都無關(guān)緊要目代,但是加上則會提供一層編譯檢查的保障。如果不符合,則會報(bào)錯(cuò)像啼。
需要注意的是:接口中只能存在一個(gè)抽象方法
格式:
修飾符 interface 接口名稱{
public abstract 返回值 方法名稱(參數(shù)列表)
// 其他方式
}
// public abstract 可以不寫 編譯器自動(dòng)加上
修飾符 interface 接口名稱{
返回值 方法名稱(參數(shù)列表)
// 其他方式
}
調(diào)用舉例:
@FunctionalInterface // 標(biāo)明為函數(shù)式接口
public abstract MyFunctionInterface{
void method(); //抽象方法
}
public class TestFunctional {
// 定義一個(gè)含有函數(shù)式接口的方法
public static void doSomething(MyFunctionInterface functionalInterface) {
functionalInterface.method();//調(diào)用自定義函數(shù)式接口的方法
}
public static void main(String[] args) {
//調(diào)用函數(shù)式接口的方法
MyFunctionInterface functionalInterface = () -> System.out.println("hello!")
doSomething(functionalInterface );
}
}
常用函數(shù)式接口
接口 | 參數(shù) | 返回值 | 說明 |
---|---|---|---|
Supplier<T> | 無 | T | 供給型俘闯;無參,返回一個(gè)指定泛型的對象 |
Consumer<T> | T | 無 | 消費(fèi)型忽冻;傳入一個(gè)指定泛型的參數(shù)真朗,無返回值 |
Predicate<T> | T | Boolean | 斷言型;判斷函數(shù)僧诚,返回判斷結(jié)果true/false |
Function<T,R> | T | R | 方法型遮婶;輸入一個(gè)參數(shù),得到一個(gè)結(jié)果 |
Supplier
無參有返回值
@FunctionalInterface
public interface Supplier<T> {
T get();
}
使用:
public class TestSupplier {
public static void main(String[] args) {
// 產(chǎn)生的數(shù)據(jù)作為 sout 作為輸出
Supplier<String> supply = ()->"產(chǎn)生數(shù)據(jù)"
System.out.println(supply.get());//輸出“產(chǎn)生數(shù)據(jù)”
}
}
Consumer
有參無返回值
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
...
}
使用:
public class TestComsumer {
public static void main(String[] args) {
Consumer<String> consumer = s->System.out.println(s)
consumer.accept("hello");//輸出“hello”
}
}
Predicate
對入?yún)?shù)據(jù)進(jìn)行判斷湖笨,并返回boolean
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
...
}
使用:
public class UsePredicate {
public static void main(String[] args) {
Predicate<Integer> predicate = (x)-> x==10;
System.out.println(predicate.test(10));//輸出true
}
}
Function
將入?yún)轉(zhuǎn)為返回值R
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
使用:
// 將數(shù)字轉(zhuǎn)換為String類型
private static void numberToString() {
String apply = function.apply(12);
System.out.println("轉(zhuǎn)換結(jié)果:"+apply);
}
public static void main(String[] args) {
Function<Number, String> function = (s)->String.valueOf(s)
System.out.println("轉(zhuǎn)換結(jié)果:"+function.apply(12));//輸出“12”
}
三旗扑, Functional Java
Functional Java是一個(gè)第三方庫,是一個(gè)在Java語言中實(shí)現(xiàn)函數(shù)型編程范式的類庫慈省。
標(biāo)準(zhǔn)的Java 8 也引入了很多函數(shù)型編程范式的元素臀防,比如Stream,lambda以及函數(shù)型接口边败。但在功能上Java 8 遠(yuǎn)不如Functional Java豐富袱衷,使用上也受到一定的限制。
Functional 項(xiàng)目地址: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
對應(yīng)Fuction<T,R>類笑窜, F<A, B>輸入類型為A致燥,返回值類型為B
F0沒有入?yún)ⅲ現(xiàn)有1個(gè)入?yún)⑴沤兀釉椋現(xiàn)8有8個(gè)入?yún)?br>
返回值類型都只有一個(gè),最后那個(gè)類型參數(shù)代表返回值類型断傲。
F<Integer, Integer> twice = n -> n * 2;
F2<Integer, Integer, Integer> f = (a, b) -> a + b;
F3<Integer, Integer, Integer, Integer> g = (a, b, c) -> a + b + c;
Effect0, Effect1, Effect2, …, Effect8
沒有返回值的函數(shù)接口類型, 對應(yīng)Consumer
Effect0沒有入?yún)⑼阎ǎ珽ffect1有1個(gè)入?yún)ⅲ险郑珽ffect8有8個(gè)入?yún)?/p>
Effect1<Integer> abc = n -> System.out.println(n);
FJ 接口 | FJ 方法 | Java 8 接口 | Java 8 方法 |
---|---|---|---|
Effect2<T, U> | f | BiConsumer<T, U> | accept |
F2<T, U, R> | f | BiFunction<T, U, R> | apply |
F2<T, T, T> | f | BinaryOperator<T> | apply |
F2<T, U, Boolean> | f | BiPredicate<T, U> | test |
F0<Boolean> | f | BooleanSupplier | getAsBoolean |
其他特性不多做介紹了急凰。。猜年。