Java编程中的引用透明性的方法

252 阅读4分钟

什么是函数式编程?

它是一种声明式的编程方式,而不是命令式的。这种编程的基本目标是使代码更简洁,更不复杂,更可预测,并且易于测试。

功能性编程涉及某些关键概念,如纯函数不可变,状态,无赋值编程等。

命令式编程与声明式编程

在命令式编程中,我们定义了做什么任务以及如何做。而在声明式编码中,我们只指定要做什么。让我们通过一个例子来理解这一点。

// Java program to find the sum
// using imperative style of coding
import java.util.Arrays;
import java.util.List;
public class ImperativeMainTest {
	public static void main(String[] args)
	{
		List<Integer> numbers
			= Arrays.asList(11, 22, 33, 44,
							55, 66, 77, 88,
							99, 100);

		int result = 0;
		for (Integer n : numbers) {
			if (n % 2 == 0) {
				result += n * 2;
			}
		}
		System.out.println(result);
	}
}


// Java program to find the sum
// using declarative style of coding
import java.util.Arrays;
import java.util.List;
public class DeclarativeMainTest {
	public static void main(String[] args)
	{
		List<Integer> numbers
			= Arrays.asList(11, 22, 33, 44,
							55, 66, 77, 88,
							99, 100);

		System.out.println(
			numbers.stream()
				.filter(number -> number % 2 == 0)
				.mapToInt(e -> e * 2)
				.sum());
	}
}

功能性编程包含以下关键概念。

  • 函数是第一类对象
  • 纯函数
  • 高阶函数

作为第一类对象的函数

在函数式编程中,函数是语言中的第一类对象。这意味着语言支持将函数作为参数传递给其他函数,将其作为其他函数的值返回,并将其分配给变量或存储在数据结构中。在Java中,方法不是第一类对象。我们最接近的是Java Lambda表达式。

高阶函数

如果至少满足以下条件之一,一个函数就是一个高阶函数。

  • 该函数接收一个或多个函数作为参数。
  • 该函数返回另一个函数作为结果。

在Java中,我们能得到的最接近高阶函数的函数(方法)是以一个或多个lambda表达式为参数,并返回另一个lambda表达式。下面是一个Java中高阶函数的例子。

public class HigherOrderFunctionClass {

    public <T> IFactory<T> createFactory(IProducer<T> producer, IConfigurator<T> configurator) {
        return () -> {
           T instance = producer.produce();
           configurator.configure(instance);
           return instance;
        }
    }
}

请注意,createFactory()方法返回一个lambda表达式作为结果。这就是高阶函数的第一个条件。

还请注意,createFactory()方法需要两个实例作为参数,这两个实例都是接口的实现(IproducerIConfigurator )。

想象一下,这些接口看起来像这样。

public interface IFactory<T> {
   T create();
}
public interface IProducer<T> {
   T produce();
}
public interface IConfigurator<T> {
   void configure(T t);
}


正如你所看到的,所有这些接口都是功能接口。因此,它们可以通过Java lambda表达式来实现--因此,createFactory()方法是一个高阶函数。

如何在Java中实现函数式编程?

// Java 8 program to demonstrate
// a lambda expression
import java.util.Arrays;
import java.util.List;
public class FPMainTest {
	public static void main(String[] args)
	{
		Runnable r
			= ()
			-> System.out.println(
				"Running in Runnable thread");

		r.run();

		System.out.println(
			"Running in main thread");
	}
}

什么是纯函数?

一个函数是一个纯函数,如果。

  • 函数的执行没有副作用。
  • 函数的返回值只取决于传递给函数的输入参数。

下面是一个Java中纯函数(方法)的例子。

public class ObjectWithPureFunction{

    public int sum(int a, int b) {
        return a + b;
    }
}

这里是一个非纯函数的例子。

public class ObjectWithNonPureFunction{
    private int value = 0;

    public int add(int nextValue) {
        this.value += nextValue;
        return this.value;
    }
}

请注意,方法add() 使用一个成员变量来计算其返回值,它还修改了value 成员变量的状态,所以它有一个副作用。

纯函数式编程也有一套规则需要遵循。

  • 没有状态
  • 没有副作用
  • 不可变的变量
  • 倾向于递归而不是循环

什么是参照性透明?

如果一个函数在调用相同的参数值时总是返回相同的结果值,那么它就被称为参照透明。

为了实现参照透明,我们需要我们的函数是纯粹的和不可变的。

例如:"String.replace() "方法是参照透明的,因为如果 "shaurav.replace(`s`,`S`) "总是产生相同的结果,因为 "replace "方法返回新的对象,而不是将原来的对象升级。

纯函数是指代透明的表达式,纯函数应该根据传递的参数返回值,不应该影响或依赖全局状态。

例子:下面是纯函数的例子

public static int sum(int a, int b){
  return a + b;
}

所以,这个函数也是参考透明的。

参考透明性使得每个子程序都是独立的,这在实施单元测试和重构的时候非常有帮助。另外,参照透明的程序更容易阅读和理解,这也是函数编程中需要参照透明的原因之一。