文章目录
Java 8 中对核心类库的改进主要包括集合类的 API 和新引入的流 (Stream)。流使程序员得以站在更高的抽象层次上对集合进行操作。
迭代
从外部迭代到内部迭代。
外部迭代
首先调用 iterator 方法,产生一个新的 Iterator 对象,进而控制整个迭代过程,这就是外部迭代。
迭代过程通过显式调用 Iterator 对象的 hasNext 和 next 方法完成迭代。
for 循环其实是一个封装了迭代的语法糖。
内部迭代
stream() 方法的调用,该方法不是返回一个控制迭代的 Iterator 对象,而是返 回内部迭代中的相应接口:Stream。
使用stream() 方法,就是内部迭代。
实现机制
long count = list.stream().filter(e -> e.getName().equals("a")).count();
这行代码并未做什么实际性的工作,filter 只刻画出了 Stream,但没有产生新的集合。
像 filter 这样只描述 Stream,最终不产生新集合的方法叫作惰性求值方法;而像 count 这样 最终会从 Stream 产生值的方法叫作及早求值方法。
判断一个操作是惰性求值还是及早求值?
只需看它的返回值。如果返回值是 Stream, 那么是惰性求值;
如果返回值是另一个值或为空,那么就是及早求值。
使用这些操作的理想方式就是形成一个惰性求值的链,最后用一个及早求值的操作返回想要的结果,这正是它的合理之处。计数的示例也是这样运行的,但这只是最简单的情况:只含两步操作。
常用的流方法
具体的可以看下Stream类中的方法。
collect(toList())
collect(toList()) 方法由 Stream 里的值生成一个列表,是一个及早求值操作。
List<String> collected = Stream.of("a", "b", "c").collect(Collectors.toList());
这段程序展示了如何使用 collect(toList()) 方法从 Stream 中生成一个列表。
map
如果有一个函数可以将一种类型的值转换成另外一种类型,map 操作就可以 使用该函数,将一个流中的值转换成一个新的流。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class MapTest {
public static void main(String[] args) {
List<String> collected = new ArrayList<>();
for (String string : Arrays.asList("a", "b", "hello")) {
String uppercaseString = string.toUpperCase();
collected.add(uppercaseString);
}
System.out.println(collected);
List<String> collected1 = Stream.of("a", "b", "hello")
.map(e -> e.toUpperCase())
.collect(Collectors.toList());
System.out.println(collected1);
}
}
传给 map 的 Lambda 表达式只接受一个 String 类型的参数,返回一个新的 String。参数 和返回值不必属于同一种类型,但是 Lambda 表达式必须是 Function 接口的一个实例,Function 接口是只包含一个参数的普通函数接口。
filter
遍历数据并检查其中的元素时,可尝试使用 Stream 中提供的新方法 filter
long count = list.stream().filter(e -> e.getName().equals("a")).count();
filter 接受一个函数作为参数,该函数用 Lambda 表达式表示。
其返回值肯定是 true 或者 false。经过过滤, Stream 中符合条件的,即 Lambda 表达式值为 true 的元素被保留下来。该 Lambda 表达式 的函数接口就是 Predicate接口。
flatMap
flatMap 方法可用 Stream 替换值,然后将多个 Stream 连接成一个 Stream
List<Integer> together = Stream.of(Arrays.asList(1, 2), Arrays.asList(3, 4))
.flatMap(numbers -> numbers.stream())
.collect(Collectors.toList());
System.out.println(together);
List<Integer> together1 = Stream.of(Arrays.asList(1, 2), Arrays.asList(3, 4))
.flatMap(Collection::stream) //方法引用
.collect(Collectors.toList());
System.out.println(together1);
调用 stream 方法,将每个列表转换成 Stream 对象,其余部分由 flatMap 方法处理。 flatMap 方法的相关函数接口和 map 方法的一样,都是 Function 接口,只是方法的返回值 限定为 Stream 类型罢了。
max和min
Stream 上常用的操作之一是求最大值和最小值。
List<Person> persons = Arrays.asList(new Person("a", 20),
new Person("b", 30),
new Person("c", 40));
Optional<Person> young = persons.stream().min(Comparator.comparing(Person::getAge));
young.ifPresent(System.out::println);
需要传给它一个 Comparator 对象。Java 8 提 供了一个新的静态方法 comparing,使用它可以方便地实现一个比较器。(实际上这个方法接受一个函数并返回另一个函数。)
reduce
reduce 操作可以实现从一组值中生成一个值。在上述例子中用到的 count、min 和 max 方 法,因为常用而被纳入标准库中。事实上,这些方法都是 reduce 操作。
int count = Stream.of(1, 2, 3)
.reduce(0, (acc, element) -> acc + element);
// Lambda 表达式的返回值是最新的 acc,是上一轮 acc 的值和当前元素相加的结果。
System.out.println(count);
// 输出:6
Lambda 表达式就是 reducer,它执行求和操作,有两个 参数:传入 Stream 中的当前元素和 acc。将两个参数相加,acc 是累加器,保存着当前的 累加结果。
// 可以将 reduce 操作展开
BinaryOperator<Integer> accumulator = (acc, element) -> acc + element;
int count1 = accumulator
.apply(accumulator.apply(accumulator.apply(0, 1), 2), 3);
System.out.println(count1);
常用实例
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class LambdaTest {
public static void main(String[] args) {
List<Person> personList = Arrays.asList(
new Person("a", 20),
new Person("b", 30),
new Person("c", 20));
}
}
以某个属性分组
Map<Integer, List<Person>> map = personList.stream().collect(Collectors.groupingBy(Person::getAge));
获取集合中的某个属性转为集合
List<String> list = personList.stream().map(Person::getName).collect(Collectors.toList());
根据集合中的某个属性进行升序重排
List<Person> personList1 = personList.stream().sorted(Comparator.comparing(Person::getAge)).collect(Collectors.toList());
根据集合中的某个属性进行降序重排
List<Person> personList2 = personList.stream().sorted(Comparator.comparing(Person::getAge).reversed()).collect(Collectors.toList());
集合中的属性去重
List<Integer> integerList = Arrays.asList(1, 2, 3, 2, 4, 3).stream().distinct().collect(Collectors.toList());
list集合本身以某个属性作为目标去重
ArrayList<Person> collect = personList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person::getAge))), ArrayList::new));
根据集合中的某个属性过滤并获取第一个
Person person = personList.stream().filter(e -> e.getAge() == 20).findFirst().orElse(null);
根据集合中的属性转换为键值对Map
注意,不允许有重复key,存在重复key时会报错
Map<String, Person> personMap = personList.stream().collect(Collectors.toMap(Person::getName, e -> e));
获取集合中某个最大值的int数据
int i = personList.stream().mapToInt(Person::getAge).max().orElse(-1);
计算总数
int sum = personList.stream().mapToInt(Person::getAge).sum();
将List转换为List
List<Integer> intList = new ArrayList<>();
intList.add(1);
intList.add(3);
intList.add(4);
List<String> stringList = intList.stream().map(String::valueOf).collect(Collectors.toList());
List<Integer> integers = Arrays.asList(1, 2, 3, 4);
List<String> strings = integers.stream().map(x -> x + "").collect(Collectors.toList());
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/155648.html