java8 stream, map 等函数式编程的一些典型用法例子如下。
例子1: 数组元素字母小写变大写。
List<String> list= Arrays.asList("a", "b", "c", "d");
List<String> collect =list.stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println(collect); //[A, B, C, D]
例子2:数组所有元素,按某种规律计算。
List<Integer> num = Arrays.asList(1,2,3,4,5);
List<Integer> collect1 = num.stream().map(n -> n * 2).collect(Collectors.toList());
System.out.println(collect1); //[2, 4, 6, 8, 10]
例子3 对数组元素的单个元素进行处理
public static String stepCondition(List<OffsetStep> step, ExtStatementRecord singleIncomeRecord) {
String[] array = step.stream().map(item -> item.getRule().condition(item, singleIncomeRecord)).toArray(String[]::new);
return StringUtils.join(array, " AND ");
}
例子4:
改造for循环。
List<String> idcards=new ArrayList<String>();//
for(int i=0;i<users.size();i++){
idcards.add(users.get(i).getName());
}
//这种方法要写好几行代码,有没有简单点的,有,java8 API能一行搞
//定:
List<String> idcards= users.stream().map(User::getIdcard).collect(Collectors.toList())
例子5:一个java 综合例子来使用Stream, collection, Optional的例子。
private void example(int coupleID, List<Map<String, Object>> masterRecordList, List<Map<String, Object>> slaveRecordsList, List<Long> masterMarksOkIds, List<Long> slaveMarksOkIds, FieldsMergeCondition mergeCondition) {
Set<String> fieldName = getFieldName(coupleID);
Map<String, List<Map<String, Object>>> slaveGroup = slaveRecordsList.stream().collect(Collectors.groupingBy(item -> {
StringBuilder key = new StringBuilder();
fieldName.forEach(column -> key.append(Optional.ofNullable(item.get(column)).orElseGet(()->"").toString().trim()));
return key.toString();
}));
Set<String> rightFieldName = getRightFieldName(coupleID);
Map<String, Map<Object, Object>> additionalMapping = verificationCommon.getAdditionalMapping(coupleID);
for (Map<String, Object> masterRecord : masterRecordList) {
setFieldValues(verificationCommon.getParsedCondition(coupleID), masterRecord);
ConditionLinkNode parsedCondition = verificationCommon.getParsedCondition(coupleID);
Map<String, Object> mappingCondition = setMappingValues(additionalMapping, masterRecord);
StringBuilder key = new StringBuilder();
rightFieldName.forEach(column -> key.append(Optional.ofNullable(masterRecord.get(column)).orElseGet(()->"").toString().trim()));
List<Map<String, Object>> slaveList = slaveGroup.get(key.toString());
if (CollectionUtils.isEmpty(slaveList)) {
continue;
}
boolean verifyOk = false;
if (Objects.isNull(mergeCondition)) {
if (slaveList.size() > 1) {
List<Long> diffIds = slaveList.stream().map(this::getRecordId).collect(Collectors.toList());
slaveMarksOkIds.addAll(diffIds);
continue;
}
verifyOk = true;
} else {
verifyOk = merge(mergeCondition, masterRecord, slaveList, verifyOk);
}
if (verifyOk) {
Map<String, Object> slaveRecord = slaveList.get(0);
if (verifyData(parsedCondition, mappingCondition, slaveRecord)) {
slaveMarksOkIds.addAll(slaveList.stream().map(this::getRecordId).collect(Collectors.toList()));
Long masterId = getRecordId(masterRecord);
masterMarksOkIds.add(masterId);
}
}
}
}
下面是Optional的orElse和orElseGet的区别
private static String getRandomName(String[] names) {
System.out.println("Generating a name...");
return "new name";
}
String[] names = new String[]{"zhang", "wang", "li", "zhao", "wu"};
Optional.of("wang").orElse(getRandomName(names)); // 执行该句时会打印"Generating a name..."
Optional.ofNullable("wang").orElse(getRandomName(names));// 执行该句时会打印"Generating a name..."
Optional.of("wang").orElseGet(() -> getRandomName(names)); //不执行getRandomName()
注:上面Optional.of和Optional.ofNullable()返回的结果是"wang",虽然orElse()方法会执行(实际测试过)。
optional为空时:
orElse 会执行,返回orElse中的结果
orElseGet 会执行,返回orElseGet中的结果
optional有值时:
orElse 会执行,返回optional的结果
orElseGet 不会执行,返回optional的结果
结论
无论optional是否有值,orElse都会被执行。
只有optional为空时,orElseGet才会被执行。
注意,敲黑板了:
有个场景要注意。就是通过optional来操作数据库,如果查询到有数据,则update,没数据则执行insert
代码可能是这样
Optional.ofNullable(selectEntity(id)).map(update(entity)).orElse(insert(entity))
这时,如果方法上再有事物注解@transactional,那么很有可能会引起Mysql事物锁等待超时 Lock wait timeout exceeded; try restarting transaction
原因是:在同一事务内先后对同一条数据进行插入和更新操作。因为orElse是必会执行的
所以orElse中,有具体方法操作时,一定要记得使用orElseGet
另外,关于对stream() 的理解
java8中 stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或I/O channel等。
为函数式编程而生。对stream的任何修改都不会修改背后的数据源,比如对stream执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新stream。
惰式执行。stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。
可消费性。stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。
例子:Java8 用stream进行分组
List<Map<String, Object>> slaveRecordsList=new ArrayLisy<>();
//给slaveRecordsList赋值,省略....
Set<String> fieldName = getFieldName(coupleID); //得到String Set
Map<String, List<Map<String, Object>>> slaveGroup = slaveRecordsList.stream().collect(Collectors.groupingBy(item -> {
StringBuilder key = new StringBuilder();
fieldName.forEach(column -> key.append(Optional.ofNullable(item.get(column)).orElse("").toString().trim()));
return key.toString();
}));
List的stream的分组功能
public static void testStreamGroup(){
List<Student> stuList = new ArrayList<Student>();
Student stu1 = new Student("10001", "孙权", "1000101", 16, '男');
Student stu2 = new Student("10001", "曹操", "1000102", 16, '男');
Student stu3 = new Student("10002", "刘备", "1000201", 16, '男');
Student stu4 = new Student("10002", "大乔", "1000202", 16, '女');
Student stu5 = new Student("10002", "小乔", "1000203", 16, '女');
Student stu6 = new Student("10003", "诸葛亮", "1000301", 16, '男');
stuList.add(stu1);
stuList.add(stu2);
stuList.add(stu3);
stuList.add(stu4);
stuList.add(stu5);
stuList.add(stu6);
Map<String, List<Student>> collect = stuList.stream().collect(Collectors.groupingBy(Student::getClassId));
for(Map.Entry<String, List<Student>> stuMap:collect.entrySet()){
String classId = stuMap.getKey();
List<Student> studentList = stuMap.getValue();
System.out.println("classId:"+classId+",studentList:"+studentList.toString());
}
}
参考文档