Java8 函数式接口 学习笔记

一, 函数式编程

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> T 供给型;无参,返回一个指定泛型的对象
Consumer<T> T 消费型;传入一个指定泛型的参数,无返回值
Predicate<T> T Boolean 断言型;判断函数,返回判断结果true/false
Function<T,R> T R 方法型;输入一个参数,得到一个结果

Supplier

无参有返回值

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

使用:

public class TestSupplier {
    public static void main(String[] args) {
         // 产生的数据作为 sout 作为输出
        Supplier<String> supply = ()->"产生数据"
        System.out.println(supply.get());//输出“产生数据”
    }
}

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

对入参数据进行判断,并返回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

将入参T转为返回值R

@FunctionalInterface
public interface Function<T, R> {
    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<Number, String> 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<T,R>类, F<A, B>输入类型为A,返回值类型为B
F0没有入参,F有1个入参,…,F8有8个入参
返回值类型都只有一个,最后那个类型参数代表返回值类型。

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

没有返回值的函数接口类型, 对应Consumer
Effect0没有入参,Effect1有1个入参,…,Effect8有8个入参

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

其他特性不多做介绍了。。。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容