Lambda表达式
1.Predicate
java.util.function.Predicate
是 Java 8 引入的一个函数式接口,代表一个接受单一输入参数并返回布尔值(true
或 false
)的函数。它常用于流(Streams)操作中,比如过滤(filter
)或其他条件判断。
示例 1:基本用法
import java.util.function.Predicate;
public class PredicateExample {
public static void main(String[] args) {
// 创建一个Predicate,判断一个数字是否大于10
Predicate<Integer> isGreaterThan10 = num -> num > 10;
// 测试Predicate
System.out.println(isGreaterThan10.test(15)); // 输出: true
System.out.println(isGreaterThan10.test(5)); // 输出: false
}
}
示例 2:结合 and
, or
, negate
方法
Predicate
接口提供了一些默认方法,允许组合多个 Predicate
对象:
and
:将两个Predicate
组合为一个,只有当两个条件都为true
时,返回true
。or
:将两个Predicate
组合为一个,任何一个条件为true
时,返回true
。negate
:将一个Predicate
取反,即当原条件为true
时,返回false
,反之亦然。
import java.util.function.Predicate;
public class PredicateCombinationExample {
public static void main(String[] args) {
Predicate<Integer> isGreaterThan10 = num -> num > 10;
Predicate<Integer> isLessThan20 = num -> num < 20;
// 使用and组合Predicate,判断一个数字是否大于10且小于20
Predicate<Integer> isBetween10And20 = isGreaterThan10.and(isLessThan20);
System.out.println(isBetween10And20.test(15)); // 输出: true
System.out.println(isBetween10And20.test(5)); // 输出: false
// 使用or组合Predicate,判断一个数字是否小于10或大于20
Predicate<Integer> isLessThan10OrGreaterThan20 = isGreaterThan10.negate().or(isLessThan20.negate());
System.out.println(isLessThan10OrGreaterThan20.test(5)); // 输出: true
System.out.println(isLessThan10OrGreaterThan20.test(25)); // 输出: true
System.out.println(isLessThan10OrGreaterThan20.test(15)); // 输出: false
}
}
示例 3:在流中使用 Predicate
Predicate
经常与 Java 流(Streams)一起使用,尤其是在 filter
操作中,可以过滤符合条件的元素。
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class PredicateStreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(5, 10, 15, 20, 25, 30);
// 创建Predicate,判断数字是否为偶数
Predicate<Integer> isEven = num -> num % 2 == 0;
// 使用filter和Predicate来过滤偶数
List<Integer> evenNumbers = numbers.stream()
.filter(isEven)
.collect(Collectors.toList());
System.out.println(evenNumbers); // 输出: [10, 20, 30]
}
}
示例 4:使用 Predicate
作为方法参数
你还可以将 Predicate
作为方法的参数来动态传递过滤条件。
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class PredicateAsParameterExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eva");
// 过滤名字长度大于3的名字
List<String> filteredNames = filterNames(names, name -> name.length() > 3);
System.out.println(filteredNames); // 输出: [Alice, Charlie, David]
}
// 使用Predicate作为参数
public static List<String> filterNames(List<String> names, Predicate<String> predicate) {
return names.stream()
.filter(predicate)
.collect(Collectors.toList());
}
}
在这个例子中,filterNames
方法接受一个 List<String>
和一个 Predicate<String>
作为参数,从而让你可以在不同的情况下传入不同的过滤条件。
2.常用的Stream()方法:
在 Stream
中,常用的方法可以分为两大类:
- 中间操作(返回一个新的
Stream
,是惰性求值的) - 终止操作(触发流的实际计算,产生一个结果,通常是单一的值或收集后的容器)
下面是常用的 Stream
方法的详细介绍。
1. 中间操作(Intermediate Operations)
中间操作会返回一个新的 Stream
,并且是惰性求值的,意味着只有在最终操作被执行时,流才会开始处理。
filter(Predicate<? super T> predicate)
filter()
用于通过提供的 Predicate
筛选出符合条件的元素。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0) // 只选择偶数
.collect(Collectors.toList());
System.out.println(evenNumbers); // 输出: [2, 4, 6]
map(Function<? super T, ? extends R> mapper)
map()
用于将流中的每个元素应用一个函数,映射成新的元素。
List<String> words = Arrays.asList("apple", "banana", "cherry");
List<Integer> wordLengths = words.stream()
.map(String::length) // 获取字符串的长度
.collect(Collectors.toList());
System.out.println(wordLengths); // 输出: [5, 6, 6]
flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
flatMap()
将每个元素映射成一个新的流,然后将这些流"扁平化"成一个单一的流。
List<List<Integer>> listOfLists = Arrays.asList(
Arrays.asList(1, 2, 3),
Arrays.asList(4, 5),
Arrays.asList(6, 7)
);
List<Integer> flatList = listOfLists.stream()
.flatMap(List::stream) // 扁平化操作
.collect(Collectors.toList());
System.out.println(flatList); // 输出: [1, 2, 3, 4, 5, 6, 7]
distinct()
distinct()
去除流中的重复元素,返回一个去重后的流。
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
List<Integer> distinctNumbers = numbers.stream()
.distinct() // 去重
.collect(Collectors.toList());
System.out.println(distinctNumbers); // 输出: [1, 2, 3, 4, 5]
sorted()
sorted()
用于对流中的元素进行排序,返回一个排序后的流。默认是升序排序。
List<Integer> numbers = Arrays.asList(5, 3, 8, 1, 4);
List<Integer> sortedNumbers = numbers.stream()
.sorted() // 升序排序
.collect(Collectors.toList());
System.out.println(sortedNumbers); // 输出: [1, 3, 4, 5, 8]
你也可以传入自定义的 Comparator
来进行降序排序:
List<Integer> sortedNumbersDesc = numbers.stream()
.sorted((a, b) -> b - a) // 降序排序
.collect(Collectors.toList());
System.out.println(sortedNumbersDesc); // 输出: [8, 5, 4, 3, 1]
limit(long maxSize)
limit()
用于返回流中的前 n
个元素,常用于截取流的前几个元素。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> limitedNumbers = numbers.stream()
.limit(3) // 获取前 3 个元素
.collect(Collectors.toList());
System.out.println(limitedNumbers); // 输出: [1, 2, 3]
skip(long n)
skip()
用于跳过流中的前 n
个元素,返回剩余的流。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> skippedNumbers = numbers.stream()
.skip(3) // 跳过前 3 个元素
.collect(Collectors.toList());
System.out.println(skippedNumbers); // 输出: [4, 5, 6]
2. 终止操作(Terminal Operations)
终止操作会触发流的计算,通常会产生一个结果,或者将结果收集到一个容器中。终止操作执行时,流会开始处理数据。
forEach(Consumer<? super T> action)
forEach()
用于遍历流中的每个元素,常用于消费流中的数据或执行副作用操作。
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream().forEach(name -> System.out.println(name)); // 遍历输出每个名字
collect(Collector<? super T, A, R> collector)
collect()
是一个非常常用的终止操作,用于将流中的元素收集到一个容器中。常见的收集器包括 toList()
、toSet()
、joining()
等。
List<String> words = Arrays.asList("apple", "banana", "cherry");
List<String> result = words.stream()
.filter(word -> word.length() > 5)
.collect(Collectors.toList()); // 收集到 List 中
System.out.println(result); // 输出: [banana, cherry]
reduce(T identity, BinaryOperator<T> accumulator)
reduce()
用于将流中的元素进行归约操作,通常用于求和、求积等操作。它将流中的元素通过二元操作符累计为一个单一的结果。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b); // 求和
System.out.println(sum); // 输出: 15
anyMatch(Predicate<? super T> predicate)
anyMatch()
用于检查流中的元素是否有任何一个满足给定的条件。只要有一个元素满足条件,返回 true
,否则返回 false
。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean hasEven = numbers.stream()
.anyMatch(n -> n % 2 == 0); // 判断是否存在偶数
System.out.println(hasEven); // 输出: true
allMatch(Predicate<? super T> predicate)
allMatch()
用于检查流中的所有元素是否都满足给定的条件。如果所有元素都满足条件,返回 true
,否则返回 false
。
List<Integer> numbers = Arrays.asList(2, 4, 6, 8);
boolean allEven = numbers.stream()
.allMatch(n -> n % 2 == 0); // 判断是否所有元素都是偶数
System.out.println(allEven); // 输出: true
noneMatch(Predicate<? super T> predicate)
noneMatch()
用于检查流中的元素是否都不满足给定的条件。如果没有任何元素满足条件,返回 true
,否则返回 false
。
List<Integer> numbers = Arrays.asList(1, 3, 5, 7);
boolean noEven = numbers.stream()
.noneMatch(n -> n % 2 == 0); // 判断是否没有偶数
System.out.println(noEven); // 输出: true
max(Comparator<? super T> comparator)
和 min(Comparator<? super T> comparator)
max()
和 min()
分别返回流中的最大值和最小值。它们接受一个 Comparator
来进行排序。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> max = numbers.stream()
.max(Integer::compareTo); // 查找最大值
System.out.println(max.get()); // 输出: 5
Optional<Integer> min = numbers.stream()
.min(Integer::compareTo); // 查找最小值
System.out.println(min.get()); // 输出: 1
count()
count()
用于统计流中元素的数量。
List<String> words = Arrays.asList("apple", "banana", "cherry");
long count = words.stream()
.filter(word -> word.length() > 5)
.count(); // 统计长度大于 5 的元素个数
System.out.println(count); // 输出: 2
findFirst()
返回第一个元素的 Optional
。
Optional<Integer> first = Stream.of(1, 2, 3).findFirst();
findAny()
返回任意一个元素的 Optional
(常用于并行流)。
Optional<Integer> any = Stream.of(1, 2, 3).findAny();
3.创建流的常用方法
Stream.of(T… values)
Stream<String> stream = Stream.of("A", "B", "C");
Arrays.stream(T[] array)
Stream<Integer> stream = Arrays.stream(new Integer[]{1, 2, 3});
Collection.stream()
List<String> list = Arrays.asList("A", "B", "C");
Stream<String> stream = list.stream();
Stream.generate(Supplier s)
Stream<Double> randoms = Stream.generate(Math::random).limit(5);
Stream.iterate(T seed, UnaryOperator f)
产生一个无线流
Stream<Integer> infinite = Stream.iterate(1, n -> n + 1).limit(5);
infinite.forEach(System.out::println); // 输出:1, 2, 3, 4, 5
4.java Stream API中实现 求和、分组、排序、去重 等常见操作的
1. 求和
通过 reduce
或 collect
方法实现。
int sum = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
System.out.println(sum); // 输出:10
使用 mapToInt
和 sum
:
int sum = Stream.of(1, 2, 3, 4).mapToInt(Integer::intValue).sum();
System.out.println(sum); // 输出:10
对对象中的某个字段求和:
class Item {
int price;
Item(int price) { this.price = price; }
}
List<Item> items = Arrays.asList(new Item(10), new Item(20), new Item(30));
int total = items.stream().mapToInt(item -> item.price).sum();
System.out.println(total); // 输出:60
2. 分组
通过 Collectors.groupingBy
方法实现。
按字段分组:
class Person {
String name;
int age;
Person(String name, int age) { this.name = name; this.age = age; }
}
List<Person> people = Arrays.asList(
new Person("Alice", 30), new Person("Bob", 20), new Person("Charlie", 30)
);
Map<Integer, List<Person>> groupedByAge = people.stream()
.collect(Collectors.groupingBy(person -> person.age));
System.out.println(groupedByAge);
// 输出:{20=[Bob], 30=[Alice, Charlie]}
分组后统计数量:
Map<Integer, Long> ageCounts = people.stream()
.collect(Collectors.groupingBy(person -> person.age, Collectors.counting()));
System.out.println(ageCounts);
// 输出:{20=1, 30=2}
分组后求和:
Map<Integer, Integer> ageSum = people.stream()
.collect(Collectors.groupingBy(
person -> person.age,
Collectors.summingInt(person -> person.age)
));
System.out.println(ageSum);
// 输出:{20=20, 30=60}
3. 排序
通过 sorted
方法实现。
自然排序(默认排序):
Stream.of(3, 1, 4, 1, 5, 9).sorted().forEach(System.out::println);
// 输出:1, 1, 3, 4, 5, 9
自定义排序:
List<String> names = Arrays.asList("Bob", "Alice", "Charlie");
names.stream()
.sorted((a, b) -> b.compareTo(a)) // 按逆序排序
.forEach(System.out::println);
// 输出:Charlie, Bob, Alice
按对象字段排序:
List<Person> people = Arrays.asList(
new Person("Alice", 30), new Person("Bob", 20), new Person("Charlie", 25)
);
people.stream()
.sorted(Comparator.comparingInt(person -> person.age)) // 按年龄升序
.forEach(person -> System.out.println(person.name));
// 输出:Bob, Charlie, Alice
4. 去重
通过 distinct
方法实现。
去除基本类型重复元素:
Stream.of(1, 2, 2, 3, 4, 4).distinct().forEach(System.out::println);
// 输出:1, 2, 3, 4
对对象去重(需要重写 equals
和 hashCode
方法):
class Person {
String name;
int age;
Person(String name, int age) { this.name = name; this.age = age; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
return age == person.age && name.equals(person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
List<Person> people = Arrays.asList(
new Person("Alice", 30), new Person("Alice", 30), new Person("Bob", 20)
);
people.stream().distinct().forEach(person -> System.out.println(person.name));
// 输出:Alice, Bob
5. 统计
通过 Collectors
提供的各种统计方法实现
统计数量:
long count = Stream.of(1, 2, 3, 4).count();
System.out.println(count); // 输出:4
求最大值和最小值:
Optional<Integer> max = Stream.of(1, 2, 3, 4).max(Integer::compare);
Optional<Integer> min = Stream.of(1, 2, 3, 4).min(Integer::compare);
System.out.println(max.get()); // 输出:4
System.out.println(min.get()); // 输出:1
求平均值:
Double average = Stream.of(1, 2, 3, 4)
.collect(Collectors.averagingInt(Integer::intValue));
System.out.println(average); // 输出:2.5
综合统计信息(最大值、最小值、平均值等):
IntSummaryStatistics stats = Stream.of(1, 2, 3, 4)
.collect(Collectors.summarizingInt(Integer::intValue));
System.out.println(stats.getSum()); // 输出:10
System.out.println(stats.getAverage()); // 输出:2.5
System.out.println(stats.getMax()); // 输出:4
System.out.println(stats.getMin()); // 输出:1
6.合并字符串
通过 Collectors.joining
方法实现。
String result = Stream.of("A", "B", "C").collect(Collectors.joining());
System.out.println(result); // 输出:ABC
带分隔符的拼接:
String result = Stream.of("A", "B", "C").collect(Collectors.joining(", "));
System.out.println(result); // 输出:A, B, C
带前缀和后缀的拼接:
String result = Stream.of("A", "B", "C").collect(Collectors.joining(", ", "[", "]"));
System.out.println(result); // 输出:[A, B, C]