新聞中心
函數(shù)式編程functional programming(FP)要么是一種理念先進(jìn)的、應(yīng)該廣泛傳播的程序設(shè)計(jì)方法;要么是一種偏學(xué)術(shù)性的、實(shí)際用途不多的編程方式,下面為大家講解一下Java函數(shù)式編程使用方法。

一. 函數(shù)式編程
Java8所有的新特性基本基于函數(shù)式編程的思想,函數(shù)式編程的帶來,給Java注入了新鮮的活力。
下面來近距離觀察一下函數(shù)式編程的幾個特點(diǎn): ?函數(shù)可以作為變量、參數(shù)、返回值和數(shù)據(jù)類型。 ?基于表達(dá)式來替代方法的調(diào)用 ?函數(shù)無狀態(tài),可以并發(fā)和獨(dú)立使用 ?函數(shù)無副作用,不會修改外部的變量 ?函數(shù)結(jié)果確定性;同樣的輸入,必然會有同樣的結(jié)果。 下面jdk1.8里面對函數(shù)式編程的定義。只是一個 FunctionalInterface 接口。特別的簡單。
1 @Documented
2 @Retention(RetentionPolicy.RUNTIME)
3 @Target(ElementType.TYPE)
4 public @interface FunctionalInterface {}
這個函數(shù)式接口有幾點(diǎn)以下的限制: ?唯一的抽象方法,有且僅有一個 (即所有的函數(shù)式接口,有且只能有一個抽象方法) ?加上標(biāo)注,則會觸發(fā)JavaCompiler的檢查。對于符合函數(shù)接口的接口,加不加都無關(guān)緊要,但是加上則會提供一層編譯檢查的保障。如果不符合,則會報(bào)錯。 ?不能被覆蓋之后,再聲明為抽象方法,則不算抽象方法。例如接口實(shí)現(xiàn)了Object中的方法。 ?可用于lambda類型的使用方式
二. Java8新增函數(shù)式接口
Stream的操作是建立在函數(shù)式接口的組合之上的。Java8中新增的函數(shù)式接口都在java.util.function包下。這些函數(shù)式接口可以有多種分類方式。
2.1 Function
Function是從T到R的一元映射函數(shù)。將參數(shù)T傳遞給一個函數(shù),返回R。即R = Function(T)
Function最常用的應(yīng)該是 Stream map(Function mapper);
比如List person里面有age,name…. 我傳入age,他就會返回age的集合給我。
@FunctionalInterface
public interface Function {
R apply(T t);
default Function compose(Function before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default Function andThen(Function after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static Function identity() {
return t -> t;
}
}
2.2 Predicate
Predicate是一個謂詞函數(shù),主要作為一個謂詞演算推導(dǎo)真假值存在,返回布爾值的函數(shù)。Predicate等價(jià)于一個Function的boolean型返回值的子集。
predicate最常用的莫過于 Stream filter(Predicate predicate);
比如我要過濾年齡 > 18 的人,我傳入age,判斷是否為true。為true則保留,false丟棄。
@FunctionalInterface
public interface Predicate
{
boolean test(T t);
default Predicate and(Predicate other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate negate() {
return (t) -> !test(t);
}
default Predicate or(Predicate other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static Predicate isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
2.3 Consumer
Consumer是從T到void的一元函數(shù),接受一個入?yún)⒌环祷厝魏谓Y(jié)果的操作。
Consumer最常用的肯定是 default void forEach(Consumer action) {}
這是一段forEach循環(huán)的代碼,傳入實(shí)現(xiàn)的方法,并不返回任何值。只是循環(huán)。
@FunctionalInterface
public interface Consumer {
void accept(T t);
default Consumer
andThen(Consumer after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }
三. Lambda表達(dá)式
3.1 基本語法
Lambda 的基本結(jié)構(gòu)為 (arguments) -> body,有如下幾種情況: ?參數(shù)類型可推導(dǎo)時,不需要指定類型,如 (a) -> System.out.println(a) ?當(dāng)只有一個參數(shù)且類型可推導(dǎo)時,不強(qiáng)制寫 (), 如 a -> System.out.println(a) ?參數(shù)指定類型時,必須有括號,如 (int a) -> System.out.println(a) ?參數(shù)可以為空,如 () -> System.out.println(“hello”) ?body 需要用 {} 包含語句,當(dāng)只有一條語句時 {} 可省略
3.2 Lambda原理
比如如下代碼:
List list = new ArrayList();
list.stream().filter((x) -> x >= 18)
Stream filter(Predicate predicate);
@FunctionalInterface
public interface Predicate {
boolean test(T t);
}
比如List里面存?zhèn)€個人的年齡,現(xiàn)在篩選出年齡大于等于18的人。
此時我們就可以用 list.stream().filter((x) -> x >= 18) 這就是一個典型的lambda表達(dá)式
(x) -> x >= 18 傳給 Predicate 函數(shù)式接口。
原理其實(shí)是:
JVM幫我們動態(tài)生成了一個內(nèi)部類,然后這個內(nèi)部類實(shí)現(xiàn)了 Predicate 這個函數(shù)式接口。
重寫了里面的test方法。生成的類似如下:
static final class Main$$Lambda$1 implements Predicate {
private Main$$Lambda$1() {
}
@Override
public boolean test(Integer x) {
return x >= 18;
}
}
3.3 Lambda用法
public class Main {
public static void main(String[] args) {
List list = new ArrayList();
list.add(40);
list.add(50);
list.add(20);
list.add(30);
List collect = list.stream().filter(x -> x >= 30)
.map((x) -> x + 10).sorted((x, y) -> -x.compareTo(y))
.collect(Collectors.toList());
System.out.println(collect);
}
}
這個一段很典型的Lambda + Stream的用法。 ?list.stream()獲取list的stream的流 ?filter篩選出年齡大于30的人 (里面是一個Predicate接口,返回真假) ?map做一個function映射 ?sort排序,里面是compartor
四. 總結(jié)
Lambda 表達(dá)式可以減少很多代碼,能提高生產(chǎn)力。但也要理解其原理。比如3.3中的代碼,為什么filter里面是斷言表達(dá)式,map里面是function表達(dá)式。
這都要從lambda的原理入手,也就是JVM動態(tài)生成一個內(nèi)部類,并繼承其中的抽象方法。
本次主要介紹了Java函數(shù)式編程的原理以及應(yīng)用,主要從Stream和lambda入手。通過一些簡單的概念,以及代碼,更好的理解Java的函數(shù)式編程。
掌握J(rèn)ava的函數(shù)式編程,對平時我們開發(fā)代碼,看其他人的代碼,都有很大的幫助。
分享題目:Java函數(shù)式編程使用方法
瀏覽路徑:http://www.5511xx.com/article/ccschog.html


咨詢
建站咨詢
