1、函数式接口
函数式接口(Function Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式的转换为Lambda表达式。
定义一个函数式接口如下:
@FunctionalInterface
interface GreetingService {
void sayMessage(String message);
}
JDK1.8 新增加的函数式接口:
- java.util.function
java.util.function它包含了很多类,用来支持Java的函数式编程,该包中的函数式接口有:
序号 | 接口 | Lambda表达式 | 描述 |
1 | BiConsumer<T,U> | (T,U) ->{} | 代表了一个接受两个输入参数的操作,并且不返回任何结果。 |
2 | BiFunction<T,U,R> | (T,U)->{R} | 代表了一个接受两个输入参数的方法,并且返回一个结果。 |
3 | BinaryOperator<T> | (T,T)->{T} | 代表了一个作用于两个同类型操作符的操作,并且返回了操作符同类型的结果。 |
4 | BiPredicate<T,U> | (T,U)->{boolean} | 代表了一个接收两个参数并且返回boolean值方法。 |
5 | BooleanSupplier | ()->{boolean} | 代表了boolean值结果的提供方。 |
6 | Consumer<T> | (T)->{} | 代表了接受一个输入参数并且无返回的操作。 |
7 | DoubleBinaryOperator | (double,double)->{double} | 代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。 |
8 | DoubleConsumer | (double)->{} | 代表一个接受double值参数的操作,并且不返回结果。 |
9 | DoubleFunction<R> | (double)->{R} | 代表接受一个double值参数的方法,并且返回结果。 |
10 | DoublePredicate | (double)->{boolean} | 代表一个拥有double值参数的boolean值方法。 |
11 | DoubleSupplier | ()->{double} | 代表一个double值结构的提供方。 |
12 | DoubleToIntFunction | (double)->{int} | 接受一个double类型输入,返回一个int类型结果。 |
13 | DoubleToLongFunction | (double)->{long} | 接受一个double类型输入,返回一个long类型结果。 |
14 | DoubleUnaryOperator | (double)->{double} | 接受一个参数同为类型double,返回值类型也为double 。 |
15 | Function<T,R> | (T)->{R} | 接受一个输入参数,返回一个结果。 |
16 | IntBinaryOperator | (int,int)->{int} | 接受两个参数同为类型int,返回值类型也为int 。 |
17 | IntConsumer | (int)->{} | 接受一个int类型的输入参数,无返回值 。 |
18 | IntFunction<R> | (int)->{R} | 接受一个int类型输入参数,返回一个结果 。 |
19 | IntPredicate | (int)->{boolean} | 接受一个int输入参数,返回一个布尔值的结果。 |
20 | IntSupplier | ()->{int} | 无参数,返回一个int类型结果。 |
21 | IntToDoubleFunction | (int)->{double} | 接受一个int类型输入,返回一个double类型结果 。 |
22 | IntToLongFunction | (int)->{long} | 接受一个int类型输入,返回一个long类型结果。 |
23 | IntUnaryOperator | (int)->{int} | 接受一个参数同为类型int,返回值类型也为int 。 |
24 | LongBinaryOperator | (long,long)->{long} | 接受两个参数同为类型long,返回值类型也为long。 |
25 | LongConsumer | (long)->{} | 接受一个long类型的输入参数,无返回值。 |
26 | LongFunction<R> | (long)->{R} | 接受一个long类型输入参数,返回一个结果。 |
27 | LongPredicate | (long)->{boolean} | 接受一个long输入参数,返回一个布尔值类型结果。 |
28 | LongSupplier | ()->{long} | 无参数,返回一个结果long类型的值。 |
29 | LongToDoubleFunction | (long)->{double} | 接受一个long类型输入,返回一个double类型结果。 |
30 | LongToIntFunction | (long)->{int} | 接受一个long类型输入,返回一个int类型结果。 |
31 | LongUnaryOperator | (long)->{long} | 接受一个参数同为类型long,返回值类型也为long。 |
32 | ObjDoubleConsumer<T> | (Object,double)->{} | 接受一个object类型和一个double类型的输入参数,无返回值。 |
33 | ObjIntConsumer<T> | (Object,int)->{} | 接受一个object类型和一个int类型的输入参数,无返回值。 |
34 | ObjLongConsumer<T> | (Object,long)->{} | 接受一个object类型和一个long类型的输入参数,无返回值。 |
35 | Predicate<T> | (T)->{boolean} | 接受一个输入参数,返回一个布尔值结果。 |
36 | Supplier<T> | ()->{T} | 无参数,返回一个结果。 |
37 | ToDoubleBiFunction<T,U> | (T,U)->{dobule} | 接受两个输入参数,返回一个double类型结果 |
38 | ToDoubleFunction<T> | (T)->{double} | 接受一个输入参数,返回一个double类型结果 |
39 | ToIntBiFunction<T,U> | (T,U)->{int} | 接受两个输入参数,返回一个int类型结果。 |
40 | ToIntFunction<T> | (int)->{int} | 接受一个输入参数,返回一个int类型结果。 |
41 | ToLongBiFunction<T,U> | (T,U)->{long} | 接受两个输入参数,返回一个long类型结果。 |
42 | ToLongFunction<T> | (T)->{long} | 接受一个输入参数,返回一个long类型结果。 |
43 | UnaryOperator<T> | (T)->{T} | 接受一个参数为类型T,返回值类型也为T。 |
2、Lambda表达式
Lambda表达式,也可称为闭包,它是推动Java8 发布的最重要的新特征,Lambda允许把函数作为一个方法的参数传递进方法中。使用Lambda表达式可以使代码变的更加简洁紧凑。
Lambda表达式的语法格式如下:
(parameters) -> expression
或
(parameters) ->{ statements; }
以下是Lambda表达式的重要特征:
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回值。
Lambda表达式的简单例子:
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
3、方法引用
在Java8 中,方法引用是一种简化Lambda表达式的语法。它允许通过方法的名称来直接引用一个已经存在的方法,而不是像Lambda表达式那样定义个匿名函数。方法引用使代码更加简洁易读,而且可以提高代码的可维护性。
Java8 中共有四种方法引用的形式:
1.静态方法引用:ClassName::staticMethodName
// Lambda表达式写法
Function<String, Integer> parseIntLambda = str -> Integer.parseInt(str);
// 方法引用写法
Function<String, Integer> parseIntReference = Integer::parseInt;
2.实例方法引用:instance::instanceMethodName
// Lambda表达式写法
BiPredicate<String, String> startsWithLambda = (str, prefix) -> str.startsWith(prefix);
// 方法引用写法
BiPredicate<String, String> startsWithReference = String::startsWith;
3.对象方法引用:ClassName::instanceMethodName
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// Lambda表达式写法
names.forEach(str -> System.out.println(str));
// 方法引用写法
names.forEach(System.out::println);
4.构造方法引用:ClassName::new
// Lambda表达式写法
Supplier<List<String>> listSupplierLambda = () -> new ArrayList<>();
// 方法引用写法
Supplier<List<String>> listSupplierReference = ArrayList::new;
4、Stream
Stream是一个功能强大的用于处理集合数据的工具。Stream API提供了一种更简洁、更易读的方式来操作集合,使得数据处理更具有函数式编程风格。
下面是Java8 Stream的基本用法和一些常用操作:
1、创建Stream:
- 从集合创建:List<String> list = Arrays.asList("a", "b", "c"); Stream<String> stream = list.stream();
- 从数组创建:Stream<String> stream = Stream.of("a", "b", "c");
- 使用Stream.of()创建单个元素的Stream:Stream<String> stream = Stream.of("a");
- 使用Stream.generate()创建无限Stream:Stream<Integer> infiniteStream = Stream.generate(() -> 1);
2、中间操作:
- filter(Predicate<T> predicate): 过滤满足条件的元素。
- map(Function<T, R> mapper): 将元素按照指定映射关系转换为另一种类型。
- distinct(): 去除重复元素。
- sorted(): 对元素进行自然排序。
- limit(long maxSize): 限制Stream的元素个数。
- skip(long n): 跳过前n个元素。
3、终端操作:
- forEach(Consumer<T> action): 对每个元素执行指定操作。
- collect(Collector<T, A, R> collector): 将Stream中的元素收集到一个集合中。
- toArray(): 将Stream转换为数组。
- reduce(BinaryOperator<T> accumulator): 将元素进行归约操作。
- min(Comparator<T> comparator): 找到最小元素。
- max(Comparator<T> comparator): 找到最大元素。
- count(): 计算Stream中的元素个数。
- anyMatch(Predicate<T> predicate): 判断是否有元素满足条件。
- allMatch(Predicate<T> predicate): 判断是否所有元素都满足条件。
- noneMatch(Predicate<T> predicate): 判断是否没有元素满足条件。
- findFirst(): 找到第一个元素。
- findAny(): 找到任意一个元素。
示例代码:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
List<String> list = Arrays.asList("apple", "banana", "orange", "apple", "grape");
// 中间操作
List<String> filteredList = list.stream()
.filter(fruit -> fruit.startsWith("a"))
.distinct()
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
System.out.println(filteredList); // Output: [APPLE]
// 终端操作
long count = list.stream()
.filter(fruit -> fruit.startsWith("a"))
.count();
System.out.println(count); // Output: 2
}
}