Java入门6: 函数式编程


Java入门6: 函数式编程

MangoGO 芒狗狗


6 函数式编程

  函数式编程(英语:functional programming)或称函数程序设计,又称泛函编程,是一种编程典范,它将计算机运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。函数编程语言最重要的基础是 \lambda 演算(lambda calculus)。而且 \lambda 演算的函数可以接受函数当作输入(引数)和输出(传出值)。

6.2 Lambda 表达式

6.2.1 Lambda 语法与案例

  一个 Lambda 表达式具有下面这样的语法特征。它由三个部分组成:第一部分为一个括号内用逗号分隔的参数列表,参数即函数式接口里面方法的参数;第二部分为一个箭头符号:->;第三部分为方法体,可以是表达式和代码块。语法如下:

parameter -> expression body

  Lambda 表达式的几个最重要的特征:

  • 可选的类型声明:你不用去声明参数的类型。编译器可以从参数的值来推断它是什么类型。
  • 可选的参数周围的括号:你可以不用在括号内声明单个参数。但是对于很多参数的情况,括号是必需的。
  • 可选的大括号:如果表达式体里面只有一个语句,那么你不必用大括号括起来。
  • 可选的返回关键字:如果表达式体只有单个表达式用于值的返回,那么编译器会自动完成这一步。若要指示表达式来返回某个值,则需要使用大括号。
// LambdaTest.java

public class LambdaTest {
   
    public static void main(String args[]){
   
        LambdaTest tester = new LambdaTest();

        // 带有类型声明的表达式
        MathOperation addition = (int a, int b) -> a + b;

        // 没有类型声明的表达式
        MathOperation subtraction = (a, b) -> a - b;

        // 带有大括号、带有返回语句的表达式
        MathOperation multiplication = (int a, int b) -> {
    return a * b; };

        // 没有大括号和return语句的表达式
        MathOperation division = (int a, int b) -> a / b;

        // 输出结果
        System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
        System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
        System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
        System.out.println("10 / 5 = " + tester.operate(10, 5, division));

        // 没有括号的表达式
        GreetingService greetService1 = message ->
        System.out.println("Hello " + message);

        // 有括号的表达式
        GreetingService greetService2 = (message) ->
        System.out.println("Hello " + message);

        // 调用sayMessage方法输出结果
        greetService1.sayMessage("MangoGO");
        greetService2.sayMessage("Classmate");
    }

    // 下面是定义的一些接口和方法

    interface MathOperation {
   
        int operation(int a, int b);
    }

    interface GreetingService {
   
        void sayMessage(String message);
    }

    private int operate(int a, int b, MathOperation mathOperation){
   
        return mathOperation.operation(a, b);
    }
}
!java LambdaTest.java
10 + 5 = 15
10 - 5 = 5
10 x 5 = 50
10 / 5 = 2
Hello MangoGO
Hello Classmate

6.2.2 Lambda 作用域

public class LambdaTest2 {
   
    final static String salutation = "Hello "; //正确,不可再次赋值
    //static String salutation = "Hello "; //正确,可再次赋值
    //String salutation = "Hello "; //报错
    //final String salutation = "Hello "; //报错

    public static void main(String args[]){
   
        //final String salutation = "Hello "; //正确,不可再次赋值
        //String salutation = "Hello "; //正确,隐性为 final , 不可再次赋值

        // salution = "welcome to "
        GreetingService greetService1 = message ->
        System.out.println(salutation + message);
        greetService1.sayMessage("MangoGO");
    }

    interface GreetingService {
   
        void sayMessage(String message);
    }
}
!java LambdaTest2.java
Hello MangoGO

  得到以下结论:

  • 可访问 static 修饰的成员变量,如果是 final static 修饰,不可再次赋值,只有 static 修饰可再次赋值;
  • 可访问表达式外层的 final 局部变量(不用声明为 final,隐性具有 final 语义),不可再次赋值。

6.3 方法引用

  方法引用提供了一个很有用的语义来直接访问类或者实例的已经存在的方法或者构造方法。

  方法引用可以通过方法的名字来引用其本身。方法引用是通过 :: 符号(双冒号)来描述的。

  它可以用来引用下列类型的方法:

  • 构造器引用。语法是 Class::new,或者更一般的 Class::new,要求构造器方法是没有参数;
  • 静态方法引用。语法是 Class::static_method。
  • 特定类的任意对象方法引用。它的语法是 Class::method。
  • 特定对象的方法引用,它的语法是 instance::method。
// LambdaTest3.java
import java.util.List;
import java.util.ArrayList;

public class LambdaTest3 {
   

    public static void main(String args[]){
   
        List<String> names = new ArrayList<>();

        names.add("Peter");
        names.add("Linda");
        names.add("Smith");
        names.add("Zack");
        names.add("Bob");

        // 通过System.out::println引用了输出的方法
        names.forEach(System.out::println);
    }
}
!java LambdaTest3.java
Peter
Linda
Smith
Zack
Bob

6.4 函数式接口

  函数式接口是只包含一个方法的接口。例如,带有单个 compareTo 方法的比较接口,被用于比较的场合。

6.4.1 java.util.function

  java.util.function 包中包含了大量的函数式接口,基本可以满足我们的日常开发需求。

接口 描述
BiConsumer<T,U> 该接口代表了接收两个输入参数 T、U,并且没有返回的操作
BiFunction<T,U,R> 该接口代表提供接收两个参数 T、U,并且产生一个结果 R 的方法
BinaryOperator 代表了基于两个相同类型的操作数,产生仍然是相同类型结果的操作
BiPredicate<T,U> 代表了对两个参数的断言操作(基于 Boolean 值的方法)
BooleanSupplier 代表了一个给出 Boolean 值结果的方法
Consumer 代表了接受单一输入参数并且没有返回值的操作
DoubleBinaryOperator 代表了基于两个 Double 类型操作数的操作,并且返回一个 Double 类型的返回值
DoubleConsumer 代表了一个接受单个 Double 类型的参数并且没有返回的操作
DoubleFunction 代表了一个接受 Double 类型参数并且返回结果的方法
DoublePredicate 代表了对一个 Double 类型的参数的断言操作
DoubleSupplier 代表了一个给出 Double 类型值的方法
DoubleToIntFunction 代表了接受单个 Double 类型参数但返回 Int 类型结果的方法
DoubleToLongFunction 代表了接受单个 Double 类型参数但返回 Long 类型结果的方法
DoubleUnaryOperator 代表了基于单个 Double 类型操作数且产生 Double 类型结果的操作
Function<T,R> 代表了接受一个参数并且产生一个结果的方法
IntBinaryOperator 代表了对两个 Int 类型操作数的操作,并且产生一个 Int 类型的结果
IntConsumer 代表了接受单个 Int 类型参数的操作,没有返回结果
IntFunction 代表了接受 Int 类型参数并且给出返回值的方法
IntPredicate 代表了对单个 Int 类型参数的断言操作

  更多的接口可以参考 Java 官方 API 手册:java.lang.Annotation Type FunctionalInterface。在实际使用过程中,加有 @FunctionalInterface 注解的方法均是此类接口,位于 java.util.Funtion 包中。

// FunctionTest.java
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class FunctionTest {
   
   public static void main(String args[]){
   
      List
  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MangoGO芒狗狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值