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的新成员,它允许以声明性方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现).就现在来说,可以把它们看成遍历数据集的高级迭代器.此外,流还可以透明地并行处理,无需写任何多 ...
随机推荐
- 深入理解Vue 3:计算属性与侦听器的艺术
title: 深入理解Vue 3:计算属性与侦听器的艺术 date: 2024/5/30 下午3:53:47 updated: 2024/5/30 下午3:53:47 categories: 前端开发 ...
- 卡方分布和 Zipf 分布模拟及 Seaborn 可视化教程
卡方分布 简介 卡方分布是一种连续概率分布,常用于统计学中进行假设检验.它描述了在独立抽样中,每个样本的平方偏差之和的分布.卡方分布的形状由其自由度 (df) 参数决定,自由度越大,分布越平缓. 参数 ...
- 使用Express写接口
接口规范 随着前后端分离越来越普遍, 后端接口规范也就越来越重要了,一套良好的接口规范可以提升工作效率, 减少沟通障碍.通常我们都会采用RestfulApi方式来提供接口, 使用 JSON 来传输数据 ...
- 用 Sentence Transformers v3 训练和微调嵌入模型
Sentence Transformers 是一个 Python 库,用于使用和训练各种应用的嵌入模型,例如检索增强生成 (RAG).语义搜索.语义文本相似度.释义挖掘 (paraphrase min ...
- Win11系统下的MindSpore环境搭建
技术背景 笔者尝试过不少编程环境搭建的方案,例如常见的Ubuntu.Deepin.CentOS,也用过很多人力荐的Manjaro,这些发行版在需要办公的条件下,一般都需要结合Windows双系统使用. ...
- helm常用命令
一.helm常用命令 1.查看帮助 helm help 2.创建一个chart包模板 格式: helm create [releasename] 例子: $helm create hello-worl ...
- ABC342
E 建反图 + 拓扑排序. 先求出直接与 \(n\) 连接的点的答,就是最后一辆车的发车时间.然后再做拓扑排序. 假如我们知道点 \(u\) 的答案为 \(ans_u\) 并且 \(u,v\) 相连, ...
- C程序函数调用&系统调用
理解程序的执行 我们要知道CPU可以自由地访问寄存器.内存.另外,程序是由操作系统执行的,所以操作系统能够控制程序的所有执行情况,限制程序的行为. 程序地执行过程: 程序是一个二进制文件,包含程序的代 ...
- tampermonkey脚本 百度搜索屏蔽CSDN
// ==UserScript==// @name 屏蔽CSDN// @namespace http://tampermonkey.net/// @version 20 ...
- 架构师必知的11种API性能优化方法
前言 接口性能优化是后端开发人员经常碰到的一道面试题,因为它是一个跟开发语言无关的公共问题. 这个问题既可以很简单,也可以相当复杂. 有时候,只需要添加一个索引就能解决. 有时候,代码需要进行重构. ...