java -- 函数式编程

这篇具有很好参考价值的文章主要介绍了java -- 函数式编程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

函数式编程

面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是怎么做
有时只是为了做某事情而不得不创建一个对象,而传递一段代码才是我们真正的目的。

Lambda

Lambda是一个匿名函数,可以理解为一段可以传递的代码。
当需要启动一个线程去完成任务时, 通常会通过java.lang.Runnable接口来定义任务内容,并使用java.lang.Thread类来启动该线程
传统写法,代码如下:

public class Demo {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("多线程任务执行!");
            }
        }).start();
    }
}

借助Java 8的全新语法,上述Runnable接口的匿名内部类写法可以通过更简单的Lambda表达式达到同样的效果:

public class Demo04LambdaRunnable {
    public static void main(String[] args) {
        new Thread(() -> System.out.println("多线程任务执行!")).start(); // 启动线程
    }
}

Lambda的优点 简化匿名内部类的使用,语法更加简单。

前提条件

必须是接口, 接口中有且只有一个抽象方法

有且仅有一个抽象方法的接口,称为函数式接口

格式

Lambda表达式的标准格式为:

() -> {}
() 参数列表,无参数留空
-> 固定写法, 代表指向动作
{} 方法体

省略规则
在Lambda标准格式的基础上,使用省略写法的规则为:

  1. 参数类型可省略
  2. 如果只有一个参数 ()可以省略
  3. 如果方法体只有一句话 return 大括号 分号都可省略, 但必须同时省略
new Thread(() -> System.out.println("省略格式开启线程")).start();

原理

  1. 在匿名方法所在类中新增一个方法,方法体为Lambda表达式中的代码
  2. 运行时形成一个新的类,并实现对应接口
  3. 重写方法的方法体中调用匿名方法所在类中新生成的方法.

函数式接口

函数式接口在Java中是指:有且仅有一个抽象方法的接口
函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。

从应用层面来讲,Java中的Lambda可以看做是匿名内部类的简化格式,但是二者在原理上不同。

格式

只要确保接口中有且仅有一个抽象方法即可:

修饰符 interface 接口名称 {
    public abstract 返回值类型 方法名称(可选参数信息);
}

由于接口当中抽象方法的public abstract是可以省略的,所以定义一个函数式接口很简单:

public interface MyFunctionalInterface {
    void myMethod();
}

@FunctionalInterface

@FunctionalInterface 该注解可用于一个接口的定义上:

@FunctionalInterface
public interface MyFunctionalInterface {
    void myMethod();
}

一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。不过,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口

常用函数式接口

Supplier接口

java.util.function.Supplier<T>接口,它意味着"供给" , 对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。
抽象方法:
T get() 用来获取一个泛型参数指定类型的对象数据
求数组元素最大值
使用Supplier接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值

public class supplierInterface {
    public static void main(String[] args) {
        int[] arr = {3,24,346,4,13};
        method(() -> {
            Arrays.sort(arr);
            return arr[arr.length - 1];
        });
    }

    public static void method(Supplier<Integer> s) {
        Integer max = s.get();
        System.out.println(max);
    }
}
Consumer接口

java.util.function.Consumer<T> 接口不生产数据,而是消费一个数据,其数据类型由泛型参数决定
抽象方法
void accept(T t),意为消费一个指定泛型的数据
默认方法
default Consumer<T> andThen(Consumer<? super T> after)

public class _4_consumerInterface {
    public static void main(String[] args) {
        method("Hello World", (String s) -> {
            System.out.println(s.toUpperCase());
        });

        method("HEllO WorlD", s -> System.out.println(s.toLowerCase()));

        System.out.println("==========================");
        method("HEllO WorlD", (String s) -> {
            System.out.println(s.toUpperCase());
        }, (String s) -> {
            System.out.println(s.toLowerCase());
        });
        method("HEllO WorlD",
                s -> System.out.println(s.toUpperCase()),
                s -> System.out.println(s.toLowerCase())
        );
    }

    public static void method(String s, Consumer<String> c) {
        c.accept(s);
    }
    public static void method(String s, Consumer<String> c1, Consumer<String> c2) {
//        c1.accept(s);
//        c2.accept(s);
        // andThen c1.accept(s)后执行c2.accept(s) 等同于上面的写法
        c1.andThen(c2).accept(s);
    }
}
Function接口

java.util.function.Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件
抽象方法:
R apply(T t) 根据类型T的参数获取类型R的结果

public class Test {
    public static void main(String[] args) {
        Function<String,Integer> f = new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.parseInt(s);
            }
        };

        Integer apply = f.apply("100");
        System.out.println(apply);

        Function<String,Integer> f2 = s -> Integer.parseInt(s);
        System.out.println(f2.apply("200"));
    }
}

默认方法:andThen

Function接口中有一个默认的andThen方法,用来进行组合操作,与Consumer接口相同

public class Test {
    public static void main(String[] args) {
        method5("10", (String s) -> {
            return Integer.parseInt(s);
        }, (Integer i) -> {
            return i * 10;
        });
        method5("100", s -> Integer.parseInt(s), i -> i * 10);
        method5("1000", Integer::parseInt, i -> i * 10);
    }
    private static void method5(String s, Function<String, Integer> f1, Function<Integer, Integer> f2) {
//        Integer i = f1.apply(s);
//        Integer n = f2.apply(i);
        Integer n = f1.andThen(f2).apply(s);
        System.out.println(n);
    }
}

Function的前置条件泛型和后置条件泛型可以相同

Predicate接口

java.util.function.Predicate 判断型接口
抽象方法: boolean test(T t) 返回boolean

public class predicateInterface {
    public static void main(String[] args) {
        method("HelloWorld.java", (String s) -> {
            return s.toLowerCase().endsWith(".java");
        });

        method("Hello.java", s -> s.toLowerCase().endsWith(".java"));

    }
    public static void method(String filename, Predicate<String> p) {
        boolean b = p.test(filename);
        System.out.println(b);
    }
}

默认方法
Predicate<T> and(Predicate<? super T> other) 并且, 底层使用 &&
Predicate<T> or(Predicate<? super T> other) 或者, 底层使用 ||
Predicate<T> negate() 取反, 底层使用 !

public class Test {
    public static void main(String[] args) {
        method("Helloworld" ,s -> s.contains("H"), s -> s.contains("W"));
    }
    private static void method(String str ,Predicate<String> one, Predicate<String> two) {
        boolean b1 = one.test(str);
        boolean b2 = two.test(str);
        System.out.println("字符串符合要求吗:" + (b1 && b2));

        boolean isValid = one.and(two).test(str);
        System.out.println("字符串符合要求吗:" + isValid);
    }
}

public class Test {
    public static void main(String[] args) {
        method("Helloworld" ,s -> s.contains("H"), s -> s.contains("W"));
    }
    private static void method(String str ,Predicate<String> one, Predicate<String> two) {
        boolean b1 = one.test(str);
        boolean b2 = two.test(str);
        System.out.println("字符串符合要求吗:" + (b1 || b2));

        boolean isValid = one.or(two).test(str);
        System.out.println("字符串符合要求吗:" + isValid);
    }
}


public class Test {
    public static void main(String[] args) {
       isLong("aaa", new Predicate<String>() {
           @Override
           public boolean test(String s) {
               return  s.length()<5;
           }
       });
       isLong("bbbaa",s -> s.length()>=5);
    }
    public static void isLong(String s , Predicate<String> p){
        boolean test = p.test(s);
        System.out.println(!test);
        boolean b2 =  p.negate().test(s);
        System.out.println(b2);
    }
}

方法引用

前提

Lambda表达式中只有一句话时 可能使用

格式

符号表示 : ::
符号说明 : 双冒号为方法引用运算符,而它所在的表达式被称为方法引用
推导与省略 : ** 如果使用Lambda,那么根据“可推导就是可省略**”的原则,无需指定参数类型,也无需指定的重载形式——它们都将被自动推导

应用Lambda表达式 , 在accept方法中接收字符串 , 目的就是为了打印显示字符串 , 那么通过Lambda来使用它的代码很简单:

public class DemoPrintSimple {
    private static void printString(Consumer<String> data, String str) {
        data.accept(str);
    }
    public static void main(String[] args) {
      	printString(s -> System.out.println(s), "Hello World");
    }
}

使用方法引用进行简化文章来源地址https://www.toymoban.com/news/detail-419620.html

public class DemoPrintRef {
    private static void printString(Consumer<String> data, String str) {
        data.accept(str);
    }
    public static void main(String[] args) {
      	printString(System.out::println, "HelloWorld");
    }
}

其他引用

public class _5_functionInterface {
    public static void main(String[] args) {
        method("100", (String s) -> {
            return Integer.parseInt(s);
        });
        method("10", s -> Integer.parseInt(s));
        /*
            类名引用静态方法
                类名::方法名
         */
        method("1000", Integer::parseInt);
        /*
            类名引用构造方法
                类名::new
         */
        method2("张三", Person::new);
        method2("李四", Person::new);
        method2("王五", s -> new Person(s));
        method3(Person::new);
         /*
            数组引用构造方法
                数据类型[]::new
         */
        method4(5,int[]::new);
        method4(3, (Integer i) -> {
            return new int[i];
        });
        method4(1, i -> new int[i]);

    }

    public static void method(String s, Function<String, Integer> f) {
        Integer n = f.apply(s);
        System.out.println(n);
    }
    private static void method2(String s, Function<String, Person> f) {
        Person p = f.apply(s);
        System.out.println(p);
    }
    private static void method3(Supplier<Person> su) {
        Person p = su.get();
        System.out.println(p);
    }
    private static void method4(Integer i, Function<Integer, int[]> f) {
        int[] arr = f.apply(i);
        System.out.println(Arrays.toString(arr));
    }
}
class Person {
    private String name;

    public Person() {}
    public Person(String name) {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

到了这里,关于java -- 函数式编程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java——面向对象编程思想

    如果有人问你,C和Java的区别是什么呢? 我想大部分人肯定脱口而出的是:C是面向过程的,Java是面向对象的。 那如何理解面向过程和面向对象呢? 首先,面向过程和面向对象都是编程思想。 ①面向过程,以C语言为代表,它是按解决一个问题的的流程或者先后步骤来编程的

    2024年02月11日
    浏览(46)
  • Java面向对象编程·上

    大家好,我是晓星航。今天为大家带来的是面向对象编程相关的讲解!😀 包 (package) 是组织类的一种方式. 使用包的主要目的是保证类的唯一性. 例如, 你在代码中写了一个 Test 类. 然后你的同事也可能写一个 Test 类. 如果出现两个同名的类, 就会冲突, 导致代码不能编译通过

    2023年04月15日
    浏览(48)
  • Java面向对象编程

    A.邮件服务的设置文件 B.DHCP的设置文件 C.DNS解析的设置文件 D.网络路由的设置文件 答案:C A.本机网关设置错误 B.本机没有正确设置DNS C.对方运行的是不同的操作系统 D.二层交换机故障 答案:A A.侵入目标服务器,获取重要数据 B.采用穷举的方式获得登录账号 C.发送无效的请求

    2024年02月07日
    浏览(36)
  • 【java】面向对象的编程基础

    true false 这里输入set和get可以自动将函数补全,传参初始化在构造属性之后 cc ccccc coleak 这里说明先构造属性,再执行代码块,再初始化 静态代码块 4 4 我是静态变量初始化 我是静态代码块 我是成员变量初始化 我是普通代码块 我是构造方法 快速构造,点击生成,构造函数,

    2023年04月16日
    浏览(45)
  • C/C++面向对象(OOP)编程-回调函数详解(回调函数、C/C++异步回调、函数指针)

    本文主要介绍回调函数的使用,包括函数指针、异步回调编程、主要通过详细的例子来指导在异步编程和事件编程中如何使用回调函数来实现。 🎬个人简介:一个全栈工程师的升级之路! 📋个人专栏:C/C++精进之路 🎀CSDN主页 发狂的小花 🌄人生秘诀:学习的本质就是极致

    2024年02月03日
    浏览(39)
  • Java基础(七)面向对象编程(高级)

    回顾类中的实例变量(即非static的成员变量) 创建两个Circle对象: Circle类中的变量radius是一个实例变量(instance variable),它属于类的每一个对象,c1中的radius变化不会影响c2的radius,反之亦然。 如果想让一个成员变量被类的所有实例所共享,就用static修饰即可,称为类变量(

    2023年04月16日
    浏览(43)
  • Java奠基】实现面向对象编程方法

    目录 标准的JavaBean类 设计对象并使用 对象封装 this 构造方法 要知道对象是一个又一个能帮助我们解决问题的东西,但是这些东西并不是凭空出现的,需要我们根据设计图来进行制造,而这些一个一个的设计图就是一个一个的类。 1)类名需要见名知意 2)成员变量使用

    2024年02月06日
    浏览(47)
  • 【Java高级语法】(十)面向对象:掀开Java 的面向对象盖章时代,一起来发现OOP的有趣编程秘密!~

    面向对象编程(Object-Oriented Programming, OOP)是一种广泛应用于软件开发的编程范式 。Java是一种面向对象的编程语言,它提供了丰富的工具和特性来支持面向对象编程。本文将详细介绍Java面向对象的全部知识。 我们可以把一个Java类想象成是一个蓝图或者模具,用来创建对象。就

    2024年02月11日
    浏览(51)
  • 【Java】小白友好的面向对象编程学习笔记

    目录 OOP介绍 类和对象 方法参数 静态 包和import 构造方法 多态 访问权限 内部类 抽象 接口 枚举 匿名类 bean类 作用域 Java 是一种面向对象的编程语言,面向对象编程(Object-Oriented Programming,简称 OOP)是一种程序设计思想,它将现实世界中的事物抽象为对象,通过封装、继承

    2024年01月20日
    浏览(46)
  • 面向对象编程第一式:封装 (Java篇)

    本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. 🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念

    2024年03月19日
    浏览(64)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包