Java8 Stream流使用
Java8 Stream 流式编程
一.Lambda表达式
Lambda表达式也可以称为闭包,它是推动Java8发布的最重要新特性,lambda允许把函数作为一个方法参数传递给方法。
在Java8之前,如果我们新创建一个线程对象,需要使用匿名内部类传递我们要执行的任务,在Java8我们可以使用lambda简化这种操;
public static void main(String[] args) {
// 匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("使用匿名内部类1");
}
}).start();
// lambda表达式
new Thread(() -> {
System.out.println("使用匿名内部类2");
}).start();
}
什么是函数式接口呢?它必须满足如下条件:
- 函数式接口只能包含一个方法
- 可以包含多个默认方法default(默认方法相当于已经实现的方法,默认方法不会影响lambda表达式对接口方法的实现)
- Object类下的方法不计算在内,例如:toString()、equals()、hashCode()等方法。
限制接口类只有一个抽象方法:@FunctionalInterface注解
例如 Runnble

TreeMap 的Comparator

二. 方法引用
我们可以将lambda表达式的实现逻辑封装成一个方法,然后直接在lambda表达式函数中调用封装好的方法,称为方法引用,方法引用包括静态方法引用和动态方法引用
无返回值的
public class TestFunction {
public static void main(String[] args) {
// 静态方法引用
print(TestFunction::format1);
// 普通方法引用
print(new TestFunction()::format2);
}
public static void format1(String name, int age) {
System.out.printf("name: %s, age: %s%n", name, age);
}
public void format2(String name, int age) {
System.out.printf("name: %s, age: %s%n", name, age);
}
public static void print(PrintFunction function) {
function.print("王大", 23);
}
}
有返回值的
public class TestResultFunction {
public static void main(String[] args) {
// 静态方法引用
String nameAndAge1 = getNameAndAge("张三", 18, TestResultFunction::format1);
// 普通方法引用
String nameAndAge2 = getNameAndAge("张三", 18, new TestResultFunction()::format2);
// 使用函数调用
ResultFunction resultFunction = (name, age) -> {
return name + ":" + age;
};
String nameAndAge3 = resultFunction.getNameAndAge("张三", 18);
System.out.println(nameAndAge1);
System.out.println(nameAndAge2);
System.out.println(nameAndAge3);
}
public static String format1(String name, int age) {
return name + ":" + age;
}
public String format2(String name, int age) {
return name + ":" + age;
}
public static String getNameAndAge(String name, Integer age, ResultFunction function) {
return function.getNameAndAge(name, age);
}
}
三. 四大内置核心函数式接口
因为我们不可能每次需要用到函数式接口就去定义一个接口,这样就是重复工作,所以java给我们按照需求的类型(消费型,供给型,函数型,断言型)提供了四个规范接口,以及他们的拓展变种接口;
1. 消费型接口
无返回值,只处理数据;例如 Stream.peek; forEach; Optional.ifPresent
Consumer<T>
void accept(T t);
2. 供给型接口
没有参数,只返回数据,例如 Optional.orElseGet; Optional.orElseThrow;
Supplier<T>
T get();
例如给缓存方法提供为空的值
public class CacheUtil {
private static HashMap<String, Object> localCache = new ConcurrentHashMap<>();
public <T> T get(String key, RedisSupplier<T> redisSupplier) {
Object value = localCache.get(key);
if (Objects.isNull(value)) {
T result = redisSupplier.get();
this.set(key, result, redisSupplier.getExpire(), redisSupplier.getTimeUnit());
return result;
}
return (T) value;
}
}
3. 函数型接口
提供参数加获取返回值,例如Stream.map; Optional.map; Map.compute; Stream.mapToInt; MybatisPlus.select; MybatisPlus.eq;
Function <T, R>
R apply(T t);
4. 断言型接口
返回boolean类型值; 例如Stream.filter; Stream.anyMatch; Stream.allMatch;Optional.filter
Predicate<T>
boolean test(T t);
四.Stream流提供的常用函数
Stream提供的方法分为两种,中间处理数据的方法,和结果集收集方法;
Stream流特性:
- 不存储数据
- 不改变源数据
- 不可重复使用
中间处理方法
| 函数 | 解释 |
|---|---|
| map | 数据处理,返回新的数据流 |
| flatMap | 数据维度降级(合并列表数据) |
| filter | 过滤数据 |
| peek | 查看数据 |
| distinct | 去重 |
| sorted | 排序 |
| limit | 数据截取,默认从第一个开始 |
| skip | 跳过N个数据 |
终端收集方法
| 函数 | 解释 |
|---|---|
| forEach | 数据处理,返回新的数据流 |
| max/min/count | 最大值/最小值/计数 |
| reduce | 归约函数 |
| anyMatch | 至少匹配一个元素 |
| allMatch | 匹配所有元素 |
| noneMatch | 没有匹配到的所有元素 |
| findFirst | 在此流中查找第一个元素 |
| findAny | 在此流中查找任意一个元素,存在随机性,一般也是第一个,主要是在并行流中体现 |
| toArray | 转成数组 |
| collect | 收集器,将流转换为其他形式 |
collect收集方法
| 函数 | 解释 |
|---|---|
| toList | 将流中的元素收集到一个List中 |
| toSet | 将流中的元素收集到一个Set中 |
| toCollection | 将流中的元素收集到一个Collection中 |
| toMap | 将流中的元素映射收集到一个Map中 |
| counting | 统计流中的元素个数 |
| summingInt | 计算流中指定int字段的累加总和。针对不同类型的数字类型,有不同的方法,比如summingDouble等 |
| averagingInt | 计算流中指定int字段的平均值。针对不同类型的数字类型,有不同的方法,比如averagingLong等 |
| joining | 将流中所有元素(或者元素的指定字段)字符串值进行拼接,可以指定拼接连接符,或者首尾拼接字符 |
| maxBy | 根据给定的比较器,选择出值最大的元素 |
| minBy | 根据给定的比较器,选择出值最小的元素 |
| groupingBy | 根据给定的分组函数的值进行分组,输出一个Map对象 |
| partitioningBy | 根据给定的分区函数的值进行分区,输出一个Map对象,且key始终为布尔值类型 |
| collectingAndThen | 包裹另一个收集器,对其结果进行二次加工转换 |
| reducing | 从给定的初始值开始,将元素进行逐个的处理,最终将所有元素计算为最终的1个值输出 |
高级: 自定义Collector收集器,实现Collector接口
中间处理方法使用
map的使用
map函数的作用是遍历Collection中的元素,生成一个新的Collection
public class TestStream {
@Test
public void testMap() {
UserInfo userInfo1 = new UserInfo("张三",18,"18273416040");
UserInfo userInfo2 = new UserInfo("李四",20,"18273416040");
UserInfo userInfo3 = new UserInfo("王五",17,"18273416040");
List<UserInfo> userInfos = Arrays.asList(userInfo1, userInfo2, userInfo3);
System.out.println("*************抽取对象集合中的某个字段 返回数组***************");
String[] usernameArrays = userInfos.stream().map(UserInfo::getUsername).toArray(String[]::new);
System.out.println(Arrays.toString(usernameArrays));
System.out.println("*************抽取对象集合中的某个字段 返回集合***************");
List<String> usernameList = userInfos.stream().map(UserInfo::getUsername).collect(Collectors.toList());
System.out.println(usernameList);
System.out.println("*************对象属性修改***************");
List<UserInfo> updateList = userInfos.stream().map(item -> {
item.setAge(100);
item.setMobile("123");
return item;
}).collect(Collectors.toList());
System.out.println(updateList);
System.out.println("*************对象集合转map集合***************");
List<Map<String, Object>> mapList = userInfos.stream().map(BeanUtil::beanToMap).collect(Collectors.toList());
System.out.println(mapList);
System.out.println("*************map集合转对象集合***************");
List<UserInfo> mapToBeamList = mapList.stream().map(item -> {
UserInfo userInfo = new UserInfo();
userInfo.setUsername(item.get("username").toString());
userInfo.setMobile(item.get("mobile").toString());
userInfo.setAge((Integer) item.get("age"));
return userInfo;
}).collect(Collectors.toList());
System.out.println(mapToBeamList);
}
}
FlatMap使用
flatmap用于集合的维度降级,也可以理解成把多个Stream流合成一个流;比如多维数组,集合中的元素中包含集合;
@Test
public void testFlatMap() {
UserInfo userInfo1 = new UserInfo("张三", 18, "18273416040");
UserInfo userInfo2 = new UserInfo("李四", 20, "18273416040");
List<String> addressList1 = new ArrayList<>();
addressList1.add("北京市海淀区");
addressList1.add("广州市天河区");
userInfo1.setAddress(addressList1);
List<String> addressList2 = new ArrayList<>();
addressList2.add("广州市天河区");
addressList2.add("广州市海珠区");
userInfo2.setAddress(addressList2);
List<UserInfo> userInfos = Arrays.asList(userInfo1, userInfo2);
System.out.println(userInfos);
List<List<String>> collect1 = userInfos.stream().map(UserInfo::getAddress).collect(Collectors.toList());
// 也可以distinct
Set<String> collect2 = userInfos.stream().map(UserInfo::getAddress).flatMap(Collection::stream).
collect(Collectors.toSet());
System.out.println(collect1);
System.out.println(collect2);
}
filter peek distinct sorted 使用
public class TestStream {
@Test
public void testPage() {
String[] names = {"宋江", "卢俊义", "吴用", "公孙胜", "关胜", "林冲", "秦明", "呼延灼", "花荣", "柴进"};
String[] mobiles = {"10086", "10010"};
List<UserInfo> userInfos = new ArrayList<>();
for (int i = 0; i < 10; i++) {
UserInfo userInfo = new UserInfo(names[i], i + 17, mobiles[i % 2]);
userInfos.add(userInfo);
}
userInfos.forEach(System.out::println);
System.out.println("\n**************************** filter ******************************\n");
// filter
List<UserInfo> filters = userInfos.stream().filter(item -> item.getAge() > 24).collect(Collectors.toList());
System.out.println(filters);
System.out.println("\n***************************** peek ***************************\n");
List<UserInfo> peeks1 = userInfos.stream().peek(System.out::println).collect(Collectors.toList());
// List<UserInfo> peeks2 = userInfos.stream().peek(item -> item.setAge(0)).collect(Collectors.toList());
// System.out.println(peeks2);
System.out.println("\n***************************** distinct ***************************\n");
List<String> mobileList1 = userInfos.stream().map(UserInfo::getMobile).collect(Collectors.toList());
List<String> mobileList2 = userInfos.stream().map(UserInfo::getMobile).distinct().collect(Collectors.toList());
System.out.println(mobileList1);
System.out.println(mobileList2);
System.out.println("\n***************************** sorted ***************************\n");
// 自然顺序对流的元素进行排序。元素类必须实现Comparable接口
List<UserInfo> sorted1 = userInfos.stream().sorted().collect(Collectors.toList());
sorted1.forEach(System.out::println);
// reverseOrder降序 naturalOrder升序
List<UserInfo> sorted2 = userInfos.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
List<UserInfo> sorted3 = userInfos.stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList());
System.out.println("sorted2");
sorted2.forEach(System.out::println);
System.out.println("sorted3");
sorted3.forEach(System.out::println);
List<UserInfo> sorted4 = userInfos.stream().sorted(Comparator.comparing(UserInfo::getAge).reversed()).collect(Collectors.toList());
System.out.println("sorted4");
sorted4.forEach(System.out::println);
List<UserInfo> sorted5 = userInfos.stream().sorted(Comparator.comparingInt(UserInfo::getAge).reversed()).collect(Collectors.toList());
List<UserInfo> sorted6 = userInfos.stream().sorted((e1, e2) -> {
if (Objects.equals(e2.getAge(), e1.getAge())) {
return e1.getUsername().compareTo(e2.getUsername());
}
return Integer.compare(e2.getAge(), e1.getAge());
}).collect(Collectors.toList());
System.out.println("\n***************************** limit ***************************\n");
List<UserInfo> limit1 = userInfos.stream().limit(1).collect(Collectors.toList());
List<UserInfo> limit2 = userInfos.stream().sorted(Comparator.comparing(UserInfo::getAge).reversed())
.limit(1).collect(Collectors.toList());
System.out.println(limit1);
System.out.println(limit2);
}
}
skip limit
limit方法,它是用于限制流中元素的个数,即取前n个元素,返回新的流;
skip()方法用于跳过前面n个元素,然后再返回新的流;
public class TestStream {
@Test
public void testSkipAndLimit() {
String[] names = {"宋江", "卢俊义", "吴用", "公孙胜", "关胜", "林冲", "秦明", "呼延灼", "花荣", "柴进"};
String[] mobiles = {"10086", "10010"};
List<UserInfo> userInfos = new ArrayList<>();
for (int i = 0; i < 10; i++) {
UserInfo userInfo = new UserInfo(names[i], i + 17, mobiles[i % 2]);
userInfos.add(userInfo);
}
List<UserInfo> skip = userInfos.stream().skip(2).collect(Collectors.toList());
List<UserInfo> limit = userInfos.stream().limit(2).collect(Collectors.toList());
System.out.println("skip");
System.out.println(skip);
System.out.println("limit");
System.out.println(limit);
System.out.println("\n*****************************skip加limit 实现分页**********************\n");
long pageSize = 3;
long totalPage = 4;
for (int pageIndex = 1; pageIndex <= totalPage; pageIndex++) {
List<UserInfo> infoList = userInfos.stream().skip((pageIndex - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
System.out.println(infoList);
System.out.println();
}
}
}
终端收集方法 使用
forEach
public class TestStreamCollection {
@Test
public void testForEach() {
UserInfo userInfo1 = new UserInfo("张三", 18, "18273416040");
UserInfo userInfo2 = new UserInfo("李四", 20, "18273416040");
UserInfo userInfo3 = new UserInfo("王五", 17, "18273416040");
List<UserInfo> userInfos = Arrays.asList(userInfo1, userInfo2, userInfo3);
userInfos.stream().forEach(item -> System.out.println(item));
}
}
count
public class TestStreamCollection {
@Test
public void testCount() {
UserInfo userInfo1 = new UserInfo("张三", 18, "18273416040");
UserInfo userInfo2 = new UserInfo("李四", 20, "18273416040");
UserInfo userInfo3 = new UserInfo("王五", 17, "18273416040");
List<UserInfo> userInfos = Arrays.asList(userInfo1, userInfo2, userInfo3);
long count = userInfos.stream().count();
// Long collect = userInfos.stream().collect(Collectors.counting());
UserInfo maxUser = userInfos.stream().max(Comparator.comparing(UserInfo::getAge)).get();
// UserInfo maxUser = userInfos.stream().max(Comparator.comparingInt(UserInfo::getAge)).get();
// UserInfo maxUser = userInfos.stream().max((o1,o2)->o1.getAge()-o2.getAge()).get();
UserInfo minUser = userInfos.stream().min(Comparator.comparing(UserInfo::getAge)).get();
System.out.println("count:" + count);
System.out.println("maxUser:" + maxUser);
System.out.println("minUser:" + minUser);
}
}
reduce
public class TestStreamCollection {
@Test
public void testReduce() {
List<Integer> ids = Stream.of(1, 2, 3, 4).collect(Collectors.toList());
// 两个参数,第一个参数是上次函数执行的返回值(也称为中间结果),第二个参数是stream中的元素,
// 这个函数把这两个值相加,得到的和会被赋值给下次执行这个函数的第一个参数
//第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素
Optional<Integer> reduce = ids.stream().reduce((acc, item) -> {
acc += item;
return acc;
});
reduce.ifPresent(System.out::println);
// 从而第一次执行的时候第一个参数的值是初始值,第二个参数是Stream的第一个元素,因为开始值是已经存在的,不存在null的情况,所以返回值是确定的类型
Integer reduce1 = ids.stream().reduce(2, (acc, item) -> {
acc += item;
return acc;
});
System.out.println(reduce1);
//返回与集合中元素不同类型的值,方便我们对复杂对象做计算式和转换
// 一个参数和两个参数的reduce()只能返回与集合中元素同类型的值。
UserInfo userInfo1 = new UserInfo("张三", 18, "18273416040");
UserInfo userInfo2 = new UserInfo("李四", 20, "18273416040");
UserInfo userInfo3 = new UserInfo("王五", 17, "18273416040");
List<UserInfo> userInfos = Arrays.asList(userInfo1, userInfo2, userInfo3);
Integer sum = userInfos.stream().parallel().reduce(0,
new BiFunction<Integer, UserInfo, Integer>() {
@Override
public Integer apply(Integer integer, UserInfo userInfo) {
return integer + userInfo.getAge();
}
}, new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) {
System.out.println("integer1:" + integer + "--integer2:" + integer2);
return integer + integer2;
}
});
System.out.println(sum);
}
}
match
public class TestStreamCollection {
@Test
public void testMatch() {
UserInfo userInfo1 = new UserInfo("张三", 18, "18273416040");
UserInfo userInfo2 = new UserInfo("李四", 20, "18273416040");
UserInfo userInfo3 = new UserInfo("王五", 17, "18273416040");
List<UserInfo> userInfos = Arrays.asList(userInfo1, userInfo2, userInfo3);
boolean anyMatch = userInfos.stream().anyMatch(item -> item.getAge() > 18);
boolean allMatch = userInfos.stream().anyMatch(item -> item.getAge() > 17);
boolean noneMatch = userInfos.stream().noneMatch(item -> item.getAge() > 18);
System.out.println(anyMatch);
System.out.println(allMatch);
System.out.println(noneMatch);
}
}
find
public class TestStreamCollection {
@Test
public void testFind() {
UserInfo userInfo1 = new UserInfo("张三", 18, "18273416040");
UserInfo userInfo2 = new UserInfo("李四", 20, "18273416040");
UserInfo userInfo3 = new UserInfo("王五", 17, "18273416040");
List<UserInfo> userInfos = Arrays.asList(userInfo1, userInfo2, userInfo3);
Optional<UserInfo> first = userInfos.stream().filter(item -> item.getAge() > 18).findFirst();
Optional<UserInfo> any = userInfos.stream().findAny();
first.ifPresent(System.out::println);
any.ifPresent(System.out::println);
}
}
toArray
public class TestStreamCollection {
@Test
public void testToArray() {
UserInfo userInfo1 = new UserInfo("张三", 18, "18273416040");
UserInfo userInfo2 = new UserInfo("李四", 20, "18273416040");
UserInfo userInfo3 = new UserInfo("王五", 17, "18273416040");
List<UserInfo> userInfos = Arrays.asList(userInfo1, userInfo2, userInfo3);
UserInfo[] userInfos1 = userInfos.stream().toArray(UserInfo[]::new);
System.out.println(Arrays.toString(userInfos1));
}
}
Collect
public class TestStreamCollection {
@Test
public void testCollect() {
UserInfo userInfo1 = new UserInfo("张三", 18, "18273416040", "人力资源部");
UserInfo userInfo2 = new UserInfo("李四", 20, "18273416040", "软件研发部");
UserInfo userInfo3 = new UserInfo("王五", 17, "18273416040", "软件研发部");
List<UserInfo> userInfos = Arrays.asList(userInfo1, userInfo2, userInfo3);
// toList
List<UserInfo> collect1 = userInfos.stream().collect(Collectors.toList());
System.out.println(collect1);
// toSet
Set<UserInfo> collect2 = userInfos.stream().collect(Collectors.toSet());
System.out.println(collect2);
// toMap
Map<String, Integer> collect3 = userInfos.stream().collect(Collectors.toMap(UserInfo::getUsername, UserInfo::getAge));
Map<String, UserInfo> collect31 = userInfos.stream().collect(Collectors.toMap(UserInfo::getUsername, (item) -> item));
System.out.println(collect3);
// 求和 joining
Double collect4 = userInfos.stream().collect(Collectors.averagingInt(UserInfo::getAge));
String collect5 = userInfos.stream().map(UserInfo::getUsername).collect(Collectors.joining(","));
System.out.println(collect4);
System.out.println(collect5);
// 年龄最大的人
Optional<UserInfo> collect6 = userInfos.stream().collect(Collectors.maxBy(Comparator.comparing(UserInfo::getAge)));
System.out.println(collect6);
//分组
Map<String, List<UserInfo>> collect7 = userInfos.stream().collect(Collectors.groupingBy(UserInfo::getDept));
System.out.println(JSONUtil.toJsonStr(collect7));
// 多重分组
Map<String, Map<Integer, List<UserInfo>>> collectMap = userInfos.stream().collect(Collectors.groupingBy(UserInfo::getDept,
Collectors.groupingBy(UserInfo::getAge)));
System.out.println(JSONUtil.toJsonStr(collectMap));
//分组统计数量
Map<String, Long> collect8 = userInfos.stream().collect(Collectors.groupingBy(UserInfo::getDept,
Collectors.counting()));
Map<String, Integer> collect9 = userInfos.stream().collect(Collectors.groupingBy(UserInfo::getDept,
Collectors.summingInt(UserInfo::getAge)));
System.out.println(collect8);
System.out.println(collect9);
// collectingAndThen
UserInfo collect10 = userInfos.stream().collect(Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparing(UserInfo::getAge)
), Optional::get));
System.out.println(collect10);
}
}
Stream在组合使用才能发货最大的优势,如果仅仅只是单一的操作,其他方法也许更简单高效;
parallel
并行流(Parallel Stream)使用ForkJoinPool实现并行性,利用所有可用CPU内核的优势,并行处理任务。如果任务数超过内核数,则其余任务将等待当前正在运行的任务完成。
可以通过 Runtime.getRuntime().availableProcessors()来获取当前计算机的CPU内核数量。 默认的线程数量就是处理器的数量,也可以通过设置系统属性来改变 System.setProperty("
java.util.concurrent.ForkJoinPool.common.parallelism", "12")
使用场景
Java 使用ForkJoinPool实现并行性,ForkJoinPool派生源流并提交执行;
- 源数据流应该是可拆分的。例如:ArrayList的数据
- 在处理问题的时候确实遇到性能问题,否则请不要为了并行而并行。
- 需要确保线程之间的所有共享资源都是正确同步,否则可能会产生数据不一致问题。
下面的测试方法,cpu是AMD 5600G 情况下 未使用Parallel需要13秒,使用Parallel之后,2秒
public class ParallelStreamTest {
@Test
public void test1() {
List<Integer> data = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
data.add(i);
}
Instant start = Instant.now();
long sum = data.stream()
.map(i -> (int) Math.sqrt(i))
.map(ParallelStreamTest::performComputation)
.reduce(0, Integer::sum);
Instant end = Instant.now();
System.out.println(sum);
System.out.printf("Time taken to complete:%s秒", Duration.between(start, end).getSeconds());
}
@Test
public void test2() {
List<Integer> data = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
data.add(i);
}
Instant start = Instant.now();
long sum = data.stream().parallel()
.map(i -> (int) Math.sqrt(i))
.map(ParallelStreamTest::performComputation)
.reduce(0, Integer::sum);
Instant end = Instant.now();
System.out.println(sum);
System.out.printf("Time taken to complete:%s秒", Duration.between(start, end).getSeconds());
}
public static int performComputation(int n) {
int sum = 0;
for (int i = 1; i < 100000; i++) {
int a = (n / i);
sum += a;
}
return sum;
}
}
Stream操作debug
对stream操作的代码行打上断点,点击debug中的下图所示图标

此时会弹出一个界面,显示stream的所有操作(数据加载可能有延迟,出现没有数据的情况);上面的卡片选项代表stream流操作,下面对应的内容是操作的结果;一目了然,让我们可以清除的知道整个流执行的过程和结果;


Stream项目中使用场景
- 拉取第三方数据时,需要把数据处理完之后存库
- 集合数据同步对比(取交集,并集,差集)
- 无法使用数据库,或者数据库压力大时,在代码中对数据进行处理
Java8 Stream流使用的更多相关文章
- 【转】Java8 Stream 流详解
当我第一次阅读 Java8 中的 Stream API 时,说实话,我非常困惑,因为它的名字听起来与 Java I0 框架中的 InputStream 和 OutputStream 非常类似.但是 ...
- Java8 Stream流
第三章 Stream流 <Java8 Stream编码实战>的代码全部在https://github.com/yu-linfeng/BlogRepositories/tree/master ...
- 这么简单,还不会使用java8 stream流的map()方法吗?
一.前言 在日常的开发工作中经常碰到要处理list中数据的问题,比如从数据库中查出了很多学生,由于一些原因需要在内存中找出这些学生中的所有姓名,或者把名为"王五"的语文成绩暂时修改 ...
- 近万字总结:Java8 Stream流式处理指南
总结/朱季谦 在实际项目当中,若能熟练使用Java8 的Stream流特性进行开发,就比较容易写出简洁优雅的代码.目前市面上很多开源框架,如Mybatis- Plus.kafka Streams以及F ...
- 让代码变得优雅简洁的神器:Java8 Stream流式编程
原创/朱季谦 本文主要基于实际项目常用的Stream Api流式处理总结. 因笔者主要从事风控反欺诈相关工作,故而此文使用比较熟悉的三要素之一的[手机号]黑名单作代码案例说明. 我在项目当中,很早就开 ...
- 关于Java8 Stream流的利与弊 Java初学者,大神勿喷
题目需求: 1:第一个队伍只要名字为3个字成员的姓名,存储到新集合 2:第一个队伍筛选之后只要前3人:存储到一个新集合 3:第2个队伍只要姓张的成员姓名:存储到一个新集合 4:第2个队伍不要前2人,存 ...
- Java8 Stream流API常用操作
Java版本现在已经发布到JDK13了,目前公司还是用的JDK8,还是有必要了解一些JDK8的新特性的,例如优雅判空的Optional类,操作集合的Stream流,函数式编程等等;这里就按操作例举一些 ...
- Java8——Stream流式操作的一点小总结
我发现,自从我学了Stream流式操作之后,工作中使用到的频率还是挺高的,因为stream配合着lambda表达式或者双冒号(::)使用真的是优雅到了极致!今天就简单分(搬)享(运)一下我对strea ...
- 【JDK8】Java8 Stream流API常用操作
Java版本现在已经发布到JDK13了,目前公司还是用的JDK8,还是有必要了解一些JDK8的新特性的,例如优雅判空的Optional类,操作集合的Stream流,函数式编程等等;这里就按操作例举一些 ...
- Java8 Stream流方法
流是Java API的新成员,它允许以声明性方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现).就现在来说,可以把它们看成遍历数据集的高级迭代器.此外,流还可以透明地并行处理,无需写任何多 ...
随机推荐
- 使用Docker快速安装Redis
1.使用docker命令下一个redis的镜像 docker pull redis 2.创建 redis 的 data 目录和 conf 目录 1. cd /home/fengsir/redis 2. ...
- 安装centos7模板机[lvm版]
1. 安装centos 7模板机 准备好centos7的镜像 下载地址:http://mirrors.aliyun.com/centos/7/isos/x86_64/ 安装centos 自定义硬件: ...
- Linux间进程通信--消息队列
本系列文章主要是学习记录Linux下进程间通信的方式. 常用的进程间通信方式:管道.FIFO.消息队列.信号量以及共享存储. 参考文档:<UNIX环境高级编程(第三版)> 参考视频:Lin ...
- leetcode_2-两数相加_javascript
题目 2.两数相加 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新 ...
- 什么是浅拷贝和深拷贝,如何用 js 代码实现?
〇.简介和对比 简介 浅拷贝:只复制原始对象的第一层属性值. 如果属性值是值类型,将直接复制值,本值和副本变更互不影响: 如果是引用数据类型,则复制内存地址,因此原始对象和新对象的属性指向相同 ...
- Unity网络通信系统设计
Unity网络通信系统设计 Buffer报文 BufferEntity类作为报文基类的作用包括: 封装数据:BufferEntity类可以用来封装网络通信中的数据,方便在网络传输中进行处理和管理. 提 ...
- spring与设计模式之一工厂模式
大家都说要多阅读spring的代码,这非常在理,毕竟spring的代码是许许多多杰出工程师的结晶,是业界多年的累积. 最近也不是非常忙,所以准备记录一系列的相关代码. 工厂模式是所有人都会的模式,是最 ...
- 一个基于SSM的CRUD的标准写法
CRUD即CREATE,READ,UPDATE,DELETE的首字母的合写,意思是增读改删.前人为了便于发音和理解,改为增删改查. CRUD基本上是软件开发中中相当部分功能的最小功能模块构成,虽然软件 ...
- HarmonyOS SDK助力鸿蒙原生应用“易感知、易理解、易操作”
6月21-23日,华为开发者大会(HDC 2024)盛大开幕.6月23日上午,<HarmonyOS开放能力,使能应用原生易用体验>分论坛成功举办,大会邀请了多位华为技术专家深度解读如何通过 ...
- 为什么Linux不能在中断中睡眠
中断分析 首先来看中断的流程: 1.进入中断处理程序---> 2.保存关键上下文----> 3.开中断(sti指令)---> /* 硬中断:对应于1.2.3步骤. 在这几个步骤中,所 ...