只有一个抽象方法的接口我们称之为函数接口。
JDK的函数式接口都加上了 @FunctionalInterface 注解进行标识。但是无论是否加上该注解只要接口中只有一个抽象方法,都是函数式接口。
在Java中,抽象方法是一种没有方法体(实现代码)的方法,只有声明,而没有具体的实现。它用关键字 abstract 进行声明,通常存在于抽象类或接口中。抽象方法的存在是为了让子类或实现类强制性地提供对这个方法的具体实现。
以下是抽象方法的一些特点和规则:
没有方法体: 抽象方法只有方法声明,没有具体的实现代码。
关键字 abstract: 抽象方法使用 abstract 关键字进行声明。
存在于抽象类或接口中: 抽象方法通常存在于抽象类或接口中。如果一个类中包含抽象方法,那么该类必须被声明为抽象类。
强制子类实现: 子类继承抽象类或实现接口时,必须提供抽象方法的具体实现,否则子类也必须声明为抽象类。
下面是一个简单的例子,演示了抽象方法的使用:
abstract class Shape {
// 抽象方法,表示计算面积的操作
abstract double calculateArea();
}
class Circle extends Shape {
double radius;
Circle(double radius) {
this.radius = radius;
}
// 实现抽象方法
@Override
double calculateArea() {
return Math.PI * radius * radius;
}
}
class Rectangle extends Shape {
double length;
double width;
Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
// 实现抽象方法
@Override
double calculateArea() {
return length * width;
}
}
public class Main {
public static void main(String[] args) {
Circle circle = new Circle(5);
System.out.println("Circle Area: " + circle.calculateArea());
Rectangle rectangle = new Rectangle(4, 6);
System.out.println("Rectangle Area: " + rectangle.calculateArea());
}
}
在上述例子中,Shape 类是一个抽象类,包含了一个抽象方法 calculateArea。Circle 和 Rectangle 类都继承自 Shape 类,并分别实现了 calculateArea 方法。这样,通过抽象方法,我们可以在不同的子类中提供特定的实现,实现多态性。
在Java中,函数式接口是一个只包含一个抽象方法的接口。从Java 8开始,引入了lambda表达式和函数式接口的概念,使得函数式编程变得更加便利。以下是一些常见的函数式接口:
Runnable:
void run()Callable:
V call() throws ExceptionRunnable类似,但可以返回一个结果并抛出异常。Comparator:
int compare(T o1, T o2)ActionListener:
void actionPerformed(ActionEvent e)Callable:
V call() throws ExceptionSupplier:
T get()Consumer:
void accept(T t)Function:
R apply(T t)Predicate:
boolean test(T t)BiFunction:
R apply(T t, U u)Function类似,但接受两个参数。T apply(T t)T apply(T t1, T t2)这些函数式接口在java.util.function包中定义。它们为Lambda表达式提供了一种方便的方式,使得在Java中进行函数式编程变得更加简洁和灵活。
根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数进行消费。
Consumer 是 Java 中的一个函数式接口,用于表示接受一个参数并在处理后不返回任何结果的操作。它包含一个名为 accept 的抽象方法,该方法接受一个参数,执行某些操作,但没有返回值。
接口定义如下:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
// 其他默认方法和静态方法省略
}
Consumer 接口的泛型类型 T 表示参数的类型。你可以使用 Consumer 接口来执行各种消费操作,例如打印、修改对象的状态等。
以下是一个简单的例子,演示了如何使用 Consumer 接口:
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerExample {
public static void main(String[] args) {
// 创建一个列表
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");
// 使用 Consumer 接口打印每个名称
Consumer<String> printName = (String name) -> System.out.println(name);
// 遍历列表,并对每个元素执行 Consumer 操作
names.forEach(printName);
}
}
在这个例子中,我们创建了一个 Consumer 对象 printName,它负责打印字符串。然后,我们使用 forEach 方法遍历名字列表,并对每个名字应用 printName 操作。
注意:由于 Consumer 是一个函数式接口,因此可以使用 lambda 表达式来简化匿名类的创建。在上述例子中,(String name) -> System.out.println(name) 就是一个 Consumer 的 lambda 表达式。
根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数计算或转换,把结果返回
Function 是 Java 中的一个函数式接口,用于表示接受一个参数并返回结果的操作。它包含一个名为 apply 的抽象方法,该方法接受一个参数并返回计算的结果。
接口定义如下:
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
// 其他默认方法和静态方法省略
}
Function 接口的泛型类型 T 表示输入的参数类型,而泛型类型 R 表示返回值的类型。你可以使用 Function 接口来执行各种转换和计算操作。
以下是一个简单的例子,演示了如何使用 Function 接口:
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
// 创建一个 Function 对象,用于将字符串转换为整数
Function<String, Integer> stringToInteger = Integer::parseInt;
// 使用 apply 方法进行转换
Integer result = stringToInteger.apply("123");
System.out.println("Result: " + result); // 输出: Result: 123
}
}
在这个例子中,我们创建了一个 Function 对象 stringToInteger,它负责将字符串转换为整数。然后,我们使用 apply 方法将字符串 "123" 应用于 stringToInteger,得到转换后的整数结果。
由于 Function 是一个函数式接口,因此可以使用 lambda 表达式来简化匿名类的创建。在上述例子中,Integer::parseInt 就是一个 Function 的 lambda 表达式。
根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数条件判断,返回判断结果
Predicate 是 Java 中的一个函数式接口,用于表示一个断言(判断条件),接受一个参数并返回一个布尔值。它包含一个名为 test 的抽象方法,该方法接受一个参数并返回一个布尔值,表示是否满足某个条件。
接口定义如下:
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
// 其他默认方法和静态方法省略
}
Predicate 接口的泛型类型 T 表示输入的参数类型。你可以使用 Predicate 接口来进行各种条件判断,例如筛选集合元素、过滤数据等。
以下是一个简单的例子,演示了如何使用 Predicate 接口:
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
// 创建一个 Predicate 对象,用于判断字符串是否包含字母 "a"
Predicate<String> containsA = s -> s.contains("a");
// 创建一个字符串列表
List<String> words = Arrays.asList("apple", "banana", "orange", "grape");
// 使用 Predicate 进行筛选
System.out.println("Words containing 'a':");
for (String word : words) {
if (containsA.test(word)) {
System.out.println(word);
}
}
}
}
在这个例子中,我们创建了一个 Predicate 对象 containsA,它负责判断字符串是否包含字母 “a”。然后,我们使用该 Predicate 对象对字符串列表进行筛选,只输出包含字母 “a” 的单词。
由于 Predicate 是一个函数式接口,因此可以使用 lambda 表达式来简化匿名类的创建。在上述例子中,s -> s.contains("a") 就是一个 Predicate 的 lambda 表达式。
根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中创建对象,把创建好的对象返回。
Supplier 是 Java 中的一个函数式接口,用于表示一个生产者,不接受任何参数但返回一个结果。它包含一个名为 get 的抽象方法,该方法不接受任何参数并返回一个结果。
接口定义如下:
@FunctionalInterface
public interface Supplier<T> {
T get();
// 其他默认方法和静态方法省略
}
Supplier 接口的泛型类型 T 表示返回值的类型。你可以使用 Supplier 接口来生成或提供数据,通常在需要延迟计算或按需生成值的场景中使用。
以下是一个简单的例子,演示了如何使用 Supplier 接口:
import java.util.function.Supplier;
public class SupplierExample {
public static void main(String[] args) {
// 创建一个 Supplier 对象,用于提供随机数
Supplier<Integer> randomSupplier = () -> (int) (Math.random() * 100);
// 获取并输出随机数
int randomNumber = randomSupplier.get();
System.out.println("Random Number: " + randomNumber);
}
}
在这个例子中,我们创建了一个 Supplier 对象 randomSupplier,它负责生成一个介于 0 到 100 之间的随机整数。然后,我们使用 get 方法获取并输出这个随机数。
由于 Supplier 是一个函数式接口,因此可以使用 lambda 表达式来简化匿名类的创建。在上述例子中,() -> (int) (Math.random() * 100) 就是一个 Supplier 的 lambda 表达式。
我们在使用Predicate接口时候可能需要进行判断条件的拼接。而and方法相当于是使用&&来拼接两个判断条件。
例如:
打印作家中年龄大于17并且姓名的长度大于1的作家。
List<Author> authors = getAuthors();
Stream<Author> authorStream = authors.stream();
authorStream.filter(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getAge()>17;
}
}.and(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getName().length()>1;
}
})).forEach(author -> System.out.println(author));
我们在使用Predicate接口时候可能需要进行判断条件的拼接。而or方法相当于是使用 || 来拼接两个判断条件。
例如:
打印作家中年龄大于17或者姓名的长度小于2的作家。
// 打印作家中年龄大于17或者姓名的长度小于2的作家。
List<Author> authors = getAuthors();
authors.stream()
.filter(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getAge()>17;
}
}.or(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getName().length()<2;
}
})).forEach(author -> System.out.println(author.getName()));
Predicate接口中的方法。negate方法相当于是在判断添加前面加了个! 表示取反
例如:
打印作家中年龄不大于17的作家。
// 打印作家中年龄不大于17的作家。
List<Author> authors = getAuthors();
authors.stream()
.filter(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getAge()>17;
}
}.negate()).forEach(author -> System.out.println(author.getAge()));