众所周知,Java8提供了很多新的特性,Lambda表达式,函数式接口,Optional,新的日期类api。今天简单聊一下Stream的前世今生。
Lambda表达式我们现在已经用的很多了,而函数式接口则是为了支持Lambda表达式,Java8提供了很多内置的函数式接口,如Runnable,Comparator等是从原有的API升级来的,而有些是Java8新增的,如Consumer等。
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
类上有注解@FunctionalInterface就可以认为这是一个函数式接口,可以用在Lambda表达式中。Lambda表达式极大的简化了我们的编程
// jdk1.8之前
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("yes");
}
}).start();
// jdk1.8及以后
new Thread(() -> System.out.println("yes")).start();
为了方便我们使用Lambda表达式,Java8提供了一些内置的函数式接口
函数式接口 | 方法 | 用途 |
---|---|---|
Consumer |
void accept(T t) | 输入参数为T,没有返回 |
Supplier供给型接口 | T get() | 返回R |
Function<T, R> 函数型接口 | R apply(T t) | 输入参数为T,返回为R |
Predicate判断型接口 | boolean test(T t) | 对象是否满足条件,true为满足,false为不满足 |
我举个例子你就明白了。
@Data
@AllArgsConstructor
public class Person {
private String name;
private int age;
private int salary;
}
员工对象为Person,此时老板发话了,给我找出年龄大于20的员工把,于是就有了下面的方法
public List<Person> filterByAge(List<Person> personList) {
List<Person> resultList = Lists.newArrayList();
for (Person person : personList) {
if (person.getAge() > 20) {
resultList.add(person);
}
}
return resultList;
}
干的不错,再给我找一下工资大于2000的员工把。
public List<Person> filterBySalary(List<Person> personList) {
List<Person> resultList = Lists.newArrayList();
for (Person person : personList) {
if (person.getSalary() > 2000) {
resultList.add(person);
}
}
return resultList;
}
再给我找一下,,, 老板等等,我需要优化一下这个实现。
你发现问题了吗?2个方法只有判断条件不同,其余的部分一模一样。而且可扩展性太差,该怎么优化呢?
额,我们可以定义一个如下的接口,判断的逻辑让接口的实现类去实现
public interface Predicate<T> {
boolean test(T t);
}
public List<Person> filter(List<Person> personList, Predicate<Person> predicate) {
List<Person> resultList = Lists.newArrayList();
for (Person person : personList) {
if (predicate.test(person)) {
resultList.add(person);
}
}
return resultList;
}
上面的需求就可以用如下几行代码实现。
List<Person> filterByAgeList = filter(list, p -> p.getAge() > 20);
List<Person> filterBySalaryList = filter(list, p -> p.getSalary() > 2000);
此时老板再加筛选需求也不怕了。
等等,我们定义的Predicate接口和Java8内置的函数式接口好像。哈哈,基本上一模一样,因为类似的场景很多,所以Java8帮我们定义了一系列的接口。省的我们自己定义
函数式接口方法用途Consumer
函数式接口 | 方法 | 用途 |
---|---|---|
Consumer |
void accept(T t) | 输入参数为T,没有返回 |
Supplier供给型接口 | T get() | 返回R |
Function<T, R> 函数型接口 | R apply(T t) | 输入参数为T,返回为R |
Predicate判断型接口 | boolean test(T t) | 对象是否满足条件,true为满足,false为不满足 |
@Test
public void testCase1() {
// 10
consumeTask(10, (m) -> System.out.println(m));
}
public void consumeTask(int num, Consumer<Integer> consumer) {
consumer.accept(num);
}
@Test
public void testCase2() {
// AAA
System.out.println(strHandler("aaa", (str) -> str.toUpperCase()));
}
public String strHandler(String str, Function<String, String> function) {
return function.apply(str);
}
当然,为了方便我们的使用,还有很多其他的内置接口,看入参和返回值就能知道接口的作用
函数式接口 | 方法 |
---|---|
BiFunction<T, U, R> | R apply(T t, U u) |
BiConsumer<T, U> | void accept(T t, U u) |
ToIntFunction | int applyAsInt(T value) |
IntFunction | R apply(int value) |
在Java8之前,如果我们想对集合进行操作还是比较麻烦的。Java8设计了Stream API来简化对集合的操作,Stream API的设计基于函数式编程和lambda表达式,行云流水似的编程方式给人带来新的体验。
Stream操作分为如下三个步骤
注意当不执行终止操作的时候,中间操作不会执行
List<Integer> dataList = Arrays.asList(1, 2, 3, 4);
// 没有输出
dataList.stream().map(x -> {
System.out.println(x);
return x;});
// 输出 1 2 3 4
// 正常是换行,我这用空格代替了,下同
dataList = dataList.stream().map(x -> {
System.out.println(x);
return x;
}).collect(Collectors.toList());
// 1. Collection集合的stream()或者parallelStream()
List<String> list = Lists.newArrayList();
Stream<String> stream1 = list.stream();
// 2. 调用Arrays.stream(T[] array)静态方法
Integer[] array = {1, 2, 3};
Stream<Integer> stream2 = Arrays.stream(array);
// 3. 调用Stream.of(T... values)静态方法
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
// 4. 调用Stream.iterate(final T seed, final UnaryOperator<T> f),创建无限流
// (x) -> x + 2 为函数式接口,传入x返回x+2,0为最开始的值
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
// 一直输出 0 2 4 6 8 10 12 ...
stream4.forEach(System.out::println);
// 5. 调用调用Stream.generate(),创建无限流
Stream<Integer> stream5 = Stream.generate(() -> 10);
// 一直输出10,你可以用Random等类随机生成哈
stream5.forEach(System.out::println);
函数名 | 解释 |
---|---|
filter | 从流中排除某些元素 |
limit | 使元素不超过指定数量 |
skip | 跳过前n个元素,如果流中元素不超过n个,则返回一个空流 |
distinct | 通过hashCode()和equals()去除重复元素 |
List<Integer> list = Arrays.asList(1, 2, 3, 4);
// 1 3
list.stream().filter(x -> x % 2 == 1).forEach(System.out::println);
// 3 4
list.stream().skip(2).forEach(System.out::println);
看一下filter方法和forEach方法的定义
Stream.java
Stream<T> filter(Predicate<? super T> predicate);
void forEach(Consumer<? super T> action);
这不就是我门上面介绍的函数式接口吗?很多方法的入参其实就是一个函数式接口
函数名 | 解释 |
---|---|
map | 接收一个函数作为参数,该函数被应用到每个元素上,并将其映射成一个新的元素 |
flatMap | 接受一个函数作为参数,将流中的每一个值都转换成另一个流,然后将所有流连接成一个流 |
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
map方法的入参和返回值可以为任意值 flatMap方法的入参为任意值,返回值必须为Stream
List<String> list = Arrays.asList("abcd", "efgh");
// [Ljava.lang.String;@7b3300e5 [Ljava.lang.String;@2e5c649
list.stream().map(x -> x.split("")).forEach(System.out::println);
// a b c d e f g h
list.stream().flatMap(x -> Arrays.stream(x.split(""))).forEach(System.out::println);
解释一下这个输出,x.split("")后为数组,所以第一个输出的为数组的地址 第二个x.split("")后为数组,然后将多个数组转为多个流,将多个流合并后输出
函数名 | 解释 |
---|---|
sorted() | 自然排序,通过Comparable接口定义的规则来排序 |
sorted(Comparator) | 定制排序,通过Comparator接口定义的规则来排序 |
List<String> list = Arrays.asList("b", "a", "c");
// a b c
list.stream().sorted().forEach(System.out::println);
// c b a
list.stream().sorted((x, y) -> y.compareTo(x)).forEach(System.out::println);
函数名 | 解释 |
---|---|
allMatch | 是否匹配所有元素 |
anyMatch | 是否至少匹配一个元素 |
noneMatch | 是否没有匹配所有元素 |
findFirst | 返回第一个元素 |
findAny | 返回当前流中的任意元素 |
count | 返回当前流中元素总个数 |
max | 返回流中最大值 |
min | 返回流中最小值 |
List<Integer> list = Arrays.asList(1, 2, 3, 4);
// false
// 当list都为1时才会返回true
System.out.println(list.stream().allMatch(num -> num.equals(1)));
// true
System.out.println(list.stream().anyMatch(num -> num.equals(1)));
// 4
System.out.println(list.stream().max((x, y) -> x.compareTo(y)).get());
函数名 | 解释 |
---|---|
reduce | 归约,将流中元素反复结合起来得到一个值 |
List<Integer> list = Arrays.asList(1, 2, 3, 4);
int sum = list.stream().reduce(0, (x, y) -> x + y);
// 10
// 初始值为0,执行过程为
// x = 0 y = 1
// x = 1 y = 2
// x = 3 y = 4 ...
// 10
// 10
System.out.println(sum);
用collect方法来进行收集,方法定义如下
Stream.java
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
<R, A> R collect(Collector<? super T, A, R> collector);
当然我一般不自己实现这个接口,可以直接用Collectors工具类
@Data
@AllArgsConstructor
public class Student {
private String name;
private int age;
}
List<Student> studentList = Arrays.asList(new Student("张三", 30),
new Student("李四", 20),
new Student("王五", 20));
List<String> nameList = studentList.stream().map(Student::getName).collect(Collectors.toList());
// [张三, 李四, 王五]
System.out.println(nameList);
Set<Integer> ageSet = studentList.stream().map(Student::getAge).collect(Collectors.toSet());
// [20, 30]
System.out.println(ageSet);
LinkedHashSet<Integer> linkedHashSet =
studentList.stream().map(Student::getAge).collect(Collectors.toCollection(LinkedHashSet::new));
// [30, 20]
System.out.println(linkedHashSet);
// 总数
long count = studentList.stream().collect(Collectors.counting());
// 3
System.out.println(count);
// 平均值
double ageAvg = studentList.stream().collect(Collectors.averagingDouble(Student::getAge));
// 23.3
System.out.println(ageAvg);
// 总和
int totalAge = studentList.stream().collect(Collectors.summingInt(Student::getAge));
// 70
System.out.println(totalAge);
// 最大值
Optional<Student> student = studentList.stream().collect(Collectors.maxBy((x, y) -> x.getAge() - y.getAge()));
// Student(name=张三, age=30)
System.out.println(student.get());
// 按照年龄分组
// 还可以多级分组,按照年龄分组后,再按照其他条件分组,不再演示
Map<Integer, List<Student>> listMap = studentList.stream().collect(Collectors.groupingBy(Student::getAge));
// {20=[StreamDemo.Student(name=李四, age=20), StreamDemo.Student(name=王五, age=20)], 30=[StreamDemo.Student(name=张三, age=30)]}
System.out.println(listMap);
项目中有很多单选项需要定义相关的枚举值,前端传入后需要校验这些值是否在枚举范围内
public enum MSG_TYPE {
IMAGE((byte) 0, "图片"),
TEXT((byte) 1, "文本");
public final byte value;
public final String name;
MSG_TYPE(byte value, String name) {
this.value = value;
this.name = name;
}
}
// 模拟前端传入的参数为1
boolean isExist = Arrays.stream(MSG_TYPE.values()).anyMatch(v -> v.value == 1);
// true
System.out.println(isExist);
isExist = Arrays.stream(MSG_TYPE.values()).anyMatch(v -> v.value == 5);
// false
System.out.println(isExist);
根据学生姓名获取学生的其他信息
List<Student> studentList = Lists.newArrayList();
for (int i = 0; i < 3; i++) {
Student student = Student.builder().name("学生" + i).age(i).build();
studentList.add(student);
}
// {学生0=Student(name=学生0, age=0), 学生2=Student(name=学生2, age=2), 学生1=Student(name=学生1, age=1)}
Map<String, Student> studentMap = studentList.stream().collect(Collectors.toMap(Student::getName, student -> student));
System.out.println(studentMap);
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/DjgVxc8-rp80dJkMrERZgQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。