1. 什么是函数式编程?
函数式编程是一种编程范式,它的主要思想是将计算视为函数之间的数学关系,避免使用共享状态和可变数据。在函数式编程中,函数是一等公民,它们可以作为参数传递给其他函数,也可以返回一个函数作为结果。这种编程方式更加注重表达式的计算结果,而不是计算的过程,因此它常常被描述为"声明式"的编程风格。
在函数式编程中,程序被看作是一组函数的组合,这些函数接收输入并产生输出,而且不会对外部状态造成影响。这种无副作用的编程方式有助于减少程序的错误和提高程序的可读性和可维护性。此外,函数式编程还提供了一些方便的工具,如高阶函数、闭包和lambda表达式等,这些工具使得编写简洁而优雅的代码变得更加容易。
以下是一个使用Java 8中的Lambda表达式和Stream API实现计算列表中所有偶数平方和的代码示例:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sumOfEvenSquares = Arrays.stream(numbers) // 创建一个整数流
.filter(n -> n % 2 == 0) // 过滤出所有偶数
.map(n -> n * n) // 将每个偶数平方
.sum(); // 计算平方和
System.out.println("Sum of squares of even numbers: " + sumOfEvenSquares);
}
}
此代码利用Java 8引入的Stream API提供了一种便利的方式来进行函数式编程,使得代码更加简洁、易读。
2. Stream中常用方法?
- filter(Predicate predicate):使用指定的条件过滤出符合条件的元素。
- map(Function<T, R> mapper):将每个元素映射为另一个元素,形成一个新的Stream。
- flatMap(Function<T, Stream>
mapper):将每个元素映射为一个Stream,然后将多个Stream合并为一个Stream。 - distinct():去除Stream中重复的元素。
- sorted():对Stream中的元素进行排序。
- peek(Consumer action):对Stream中的每个元素执行指定的操作,返回一个与原Stream相同的Stream。
- limit(long maxSize):截取Stream中的前maxSize个元素。
- skip(long n):跳过Stream中的前n个元素。
- forEach(Consumer action):对Stream中的每个元素执行指定的操作。
- reduce(T identity, BinaryOperator
accumulator):使用指定的初始值和累加器对Stream中的元素进行归约。 - collect(Collector<T, A, R> collector):将Stream中的元素收集到一个容器中。
3. 如何自定义函数式接口?
自定义函数接口可以使用@FunctionalInterface注解来声明。一个函数接口要求只有一个抽象方法,这个注解会告诉编译器,这个接口应该只有一个抽象方法,如果这个接口定义了多个抽象方法,编译器将会报错。
以下是一个自定义函数接口的示例:
@FunctionalInterface
public interface MyFunction<T, R> {
R apply(T t);
}
这个自定义的函数接口叫做MyFunction,它有一个泛型类型参数T和一个泛型类型参数R。其中T是输入类型,R是输出类型。它只有一个抽象方法apply(T t),它接收一个T类型的参数并返回一个R类型的结果。该接口被@FunctionalInterface注解所修饰,因此编译器会强制检查它是否符合函数接口的规则。
使用自定义的函数接口时,可以像使用Java标准库中的函数接口一样使用它。例如,可以创建一个lambda表达式来实现该接口的抽象方法,或者创建一个实现该接口的类的实例。
以下是一个使用自定义函数接口的示例:
public class Main {
public static void main(String[] args) {
MyFunction<String, Integer> myFunction = s -> s.length();
int length = myFunction.apply("Hello, world!");
System.out.println("Length of string: " + length);
}
}
在上面的李子中,我们创建了一个MyFunction类型的对象myFunction,并使用lambda表达式实现了它的抽象方法。然后我们使用apply方法将一个字符串传递给myFunction对象,该方法返回字符串的长度并将其存储在length变量中。最后我们输出这个长度值。