1. 代码规范
stream流的应用:注意最终的返回要调用的不是流的话就是以终端操作的流进行将流生成一个结果
List<String> words = Arrays.asList("apple", "banana", "apple", "orange");
// 中间操作链
Stream<String> stream = words.stream()
.filter(w -> w.startsWith("a"))
.map(String::toUpperCase)
.sorted();
// 必须有终端操作来完成流的处理
List<String> result = stream.collect(Collectors.toList());
中间调用:这些操作后还会返回新的流
-
filter()只保留满足条件的元素
-
dinstinct():去重
-
sorted():返回按定义的排序方式的数据
-
peek():对流中每个元素进行操作(通常用于调试)
-
map():将流中的每个元素映射到另外的流中
-
flatMap():将流中的每个元素映射成一个流,然后将流整合成一个流
-
limit()
-
skip()
-
takeWhile和dropwhile
终端操作:将流生成一个结果:
-
foreach()
-
toArray():将流转成数组
-
reduce():将流中所有元素归纳为一个值
-
collect():将流转换成列表或者集合
-
min()/max()
-
count()
-
sum()
-
average()
-
sumLong()
-
filndFirst()
-
findAny()
-
anyMatch()
-
allMatch()
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class StreamExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "apple", "orange");
// filter() - 只保留满足条件的元素
List<String> filtered = words.stream()
.filter(w -> w.length() > 5)
.collect(Collectors.toList());
System.out.println(filtered); // [banana, orange]
// distinct() - 去重
List<String> distinctWords = words.stream()
.distinct()
.collect(Collectors.toList());
System.out.println(distinctWords); // [apple, banana, orange]
// sorted() - 返回按定义的排序方式的数据
List<String> sorted = words.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(sorted); // [apple, apple, banana, orange]
// peek() - 对流中每个元素进行操作(通常用于调试)
words.stream()
.peek(System.out::println)
.collect(Collectors.toList());
// 输出:apple, banana, apple, orange
// map() - 将流中的每个元素映射到另外的流中
List<Integer> lengths = words.stream()
.map(String::length)
.collect(Collectors.toList());
System.out.println(lengths); // [5, 6, 5, 6]
// flatMap() - 将流中的每个元素映射成一个流,然后将流整合成一个流
List<String> flatWords = Arrays.asList("a,b", "c,d,e");
List<String> flatList = flatWords.stream()
.flatMap(s -> Arrays.stream(s.split(",")))
.collect(Collectors.toList());
System.out.println(flatList); // [a, b, c, d, e]
// limit() - 限制流中元素的数量
List<String> limited = words.stream()
.limit(2)
.collect(Collectors.toList());
System.out.println(limited); // [apple, banana]
// skip() - 跳过流中的前n个元素
List<String> skipped = words.stream()
.skip(2)
.collect(Collectors.toList());
System.out.println(skipped); // [apple, orange]
// takeWhile() 和 dropWhile() - 这两个操作Java Stream API中没有直接对应方法
// 但是可以通过filter()实现类似功能
List<String> takeWhile = words.stream()
.takeWhile(Objects::nonNull)
.collect(Collectors.toList());
System.out.println(takeWhile); // [apple, banana, apple, orange]
// 因为words中没有null元素,所以这个例子不会跳过任何元素
// 终端操作
// forEach() - 对流中的每个元素执行操作
words.stream()
.forEach(System.out::println);
// 输出:apple, banana, apple, orange
// toArray() - 将流转成数组
String[] array = words.stream()
.toArray(String[]::new);
System.out.println(Arrays.toString(array)); // [apple, banana, apple, orange]
// reduce() - 将流中所有元素归纳为一个值
Optional<String> reduced = words.stream()
.reduce((s1, s2) -> s1 + " " + s2);
reduced.ifPresent(System.out::println);
// 输出:apple banana apple orange
// collect() - 将流转换成列表或者集合
Set<String> set = words.stream()
.collect(Collectors.toSet());
System.out.println(set); // [apple, banana, orange]
// min()/max() - 找出流中的最小/最大元素
Optional<String> min = words.stream()
.min(Comparator.naturalOrder());
min.ifPresent(System.out::println);
// 输出:apple
// count() - 返回流中元素的数量
long count = words.stream()
.count();
System.out.println(count); // 4
// sum() - 对流中的元素进行求和(仅适用于数值类型)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
int sum = numbers.stream()
.sum();
System.out.println(sum); // 10
// average() - 计算流中元素的平均值(仅适用于数值类型)
OptionalDouble average = numbers.stream()
.average();
average.ifPresent(System.out::println);
// 输出:2.5
// sumLong() - 对流中的元素进行求和(仅适用于long类型)
long longSum = numbers.stream()
.mapToLong(Integer::longValue)
.sum();
System.out.println(longSum); // 10
// findFirst() - 返回流中的第一个元素
Optional<String> first = words.stream()
.findFirst();
first.ifPresent(System.out::println);
// 输出:apple
// findAny() - 返回流中的任意一个元素
Optional<String> any = words.stream()
.findAny();
any.ifPresent(System.out::println);
// 输出可能是:apple(结果不确定)
// anyMatch() - 检查流中是否至少有一个元素满足给定条件
boolean anyMatch = words.stream()
.anyMatch("banana"::equals);
System.out.println(anyMatch); // true
// allMatch() - 检查流中的所有元素是否都满足给定条件
boolean allMatch = words.stream()
.allMatch("apple"::equals);
System.out.println(allMatch); // false
}
}
常见数据类型和对象容器的非空检查方法:
-
对于基本数据类型(int和double和bolean默认是0),但是对于他们的包装类需要检查是否为null
-
对于任意的对象引用都应该检查是否为null
-
数组类型需要检查是否为null,以及是否为空数组
-
对于集合(list和set)需要检查是否为null和空集合
-
映射(如
Map
),需要检查是否为null
以及是否为空映射。 -
对于空字符串需要检查是否为null以及是否为空字符串
Objects.isNull():检查对象是否为 null。
StringUtils.isEmpty(str):检查字符串是否为空和null。
StringUtils.isNotBlank(str):检查字符串是否不是空且不只包含空白字符和null。
StringUtils.isAnyBlank 方法,用于检查多个字符串中是否有任何一个为空或仅包含空白字符
StringUtils.isNumeric 方法可以判断给定的字符串是否为纯数字
-
Integer
、Long
、Double
等包装类。可以使用类似的Boolean.TRUE.equals()
方法来避免null
判断。
Integer value = ...;
if (Integer.valueOf(10).equals(value)) {
// 防止 null 的比较
}
// 或者:
Double value = ...;
if (Double.compare(value, 0.0) == 0) {
// 防止 null 和 0 的比较
}
Equals的检查使用:
-
对象的eqauls方法:
对象1.equals(对象2)
// -----------------------------------
Object obj1 = null;
Object obj2 = null;
boolean isEqual = Objects.equals(obj1, obj2); // 安全地比较,null是相等的
-
字符串和数据类型的包装类:
String str1 = "hello";
String str2 = "hello";
boolean isEqual = str1.equals(str2); // 比较字符串内容
if (Objects.equals(str1, str2)) {
// 如果 str1 和 str2 相等,且不会出现 null 引起的问题
}
Integer num1 = 10;
Integer num2 = 10;
boolean isEqual = num1.equals(num2); // 比较数值
-
数组的equals:
int[] arrays1 = new int[10];
int[] arrays2 = new int[10];
Arrays.equals(arrays1, arrays2)
-
List
、Set
和其他容器
List<String> list = ...;
if (list != null && !list.isEmpty()) {
// list 不为 null 且不为空
}
// 更简洁:
if (Objects.nonNull(list) && !list.isEmpty()) {
// list 不为 null 且不为空
}
// 对于空容器:
if (!CollectionUtils.isEmpty(list)) {
// list 不为 null 且不为空
}
-
对于
Map
,可以用Map.isEmpty()
来代替null
检查
Map<String, String> map = ...;
if (map != null && !map.isEmpty()) {
// map 不为 null 且不为空
}
if (Objects.nonNull(map) && !map.isEmpty()) {
// map 不为 null 且不为空
}
Optional的使用:
-
对于字符串和集合:
String str = "...";
Optional<String> optionalStr = Optional.ofNullable(str);
// 如果存在就打印数据
optionalStr.ifPresent(s -> {
System.out.println(s);
});
// 或者使用 orElse
String value = optionalStr.orElse("默认值");
List<String> list = new ArrayList<>();
Optional<List<String>> optionalList = Optional.ofNullable(list);
optionalList.ifPresent(l -> {
if (!l.isEmpty()) {
System.out.println("集合不为空");
}
});
// 或者使用 orElse
List<String> value = optionalList.orElseGet(Collections::emptyList);
-
对于数组:
String[] arrays = new String[];
if(ArrayUtils.isNotNull(arrays)){
}
-
对于Map:
Map<String, String> map = new HashMap<>();
Optional<Map<String, String>> optionalMap = Optional.ofNullable(map);
optionalMap.ifPresent(m -> {
if (!m.isEmpty()) {
System.out.println("映射不为空");
}
});
// 或者使用 orElse
Map<String, String> value = optionalMap.orElseGet(Collections::emptyMap);
-
对于自定义对象:
MyObject obj = new MyObejct();
Optional<MyObject> optionalObj = Optional.ofNullable(obj);
optionalObj.ifPresent(o -> {
// 使用 o
});
// 或者使用 orElse
MyObject value = optionalObj.orElse(new MyObject());
不同类型和对象容器的类型转换方法和注意的地方,且要时刻注意要转的数据为Null的情况:
-
转换时需要注意null引发的错误
-
首先要知道拿到的值的类型和要使用的值的类型有没有异同
可根据instanceof拿到运行时对象的实际类型
使用 Objects.requireNonNull()
进行非空检查。
Optional.ofNullable(value).orElse(defaultValue)
、
优先使用优先使用 valueOf()
而不是parse() 和强转
-
基本类型和包装类型有拆箱和装箱,但是要注意数据类型的上下转换。但是要注意null的情况
-
String转换成基本类型
// 使用数据类型的装箱的parse---方法
// 并且注意输入的转换类型必须是有效格式:比如:"abc"就转成不了int等数据
int num = Integer.parseInt("123");
double d = Double.parseDouble("3.14");
boolean bool = Boolean.parseBoolean("true");
-
基本类型转成string类型:String.valueOf(Object)
String.valueOf(null)
不会抛异常,而是 "null"
。
"" + num
会创建多个临时对象,影响性能,建议使用 String.valueOf()
。
String str = String.valueOf(123);
String str2 = Integer.toString(456);
String str3 = "" + 789; // 低效
-
数组和集合的转换:
-
数组到-List:
// Arrays.asList(array) 返回的 List 不能增删,否则抛 UnsupportedOperationException。
String[] array = {"A", "B", "C"};
List<String> list = Arrays.asList(array);
//如果需要可变:
List<String> list = new ArrayList<>(Arrays.asList(array));
-
List到数组:
String[] array = list.toArray(new String[0]); // 推荐用 new String[0]
toArray(new String[0])
比 new String[list.size()]
更优。
-
对象间的转换:
属性赋值:
// beanUtils进行属性拷贝
import org.springframework.beans.BeanUtils;
UserDTO userDTO = new UserDTO();
BeanUtils.copyProperties(userEntity, userDTO);
//企业级开发推荐使用 MapStruct 自动映射:
-
json转换类型:常使用
Jackson
、Gson
、Fastjson
等库,推荐使用Jackson
,更安全。
// java到json:
ObjectMapper objectMapper = new ObjectMapper();
User user = new User(1, "Tom", 25);
// 序列化(Java 对象 -> JSON 字符串)
String jsonString = objectMapper.writeValueAsString(user);
System.out.println(jsonString);
// json字符串转成java对象:
String jsonString = "{\"id\":1,\"name\":\"Tom\",\"age\":25}";
User user = objectMapper.readValue(jsonString, User.class);
System.out.println(user.getName()); // Tom
// 注意:日期格式:默认解析 Date 为时间戳
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
User user = new User(1, "Tom", 25);
String jsonString = JSON.toJSONString(user);
System.out.println(jsonString);
String jsonString = "{\"id\":1,\"name\":\"Tom\",\"age\":25}";
User user = JSON.parseObject(jsonString, User.class);
System.out.println(user.getName());
List<User> userList = JSON.parseArray(jsonArrayString, User.class);
//指定别名:
@JSONField(name = "user_name")
private String name;
-
日期的类型的转换
转换:
String dateStr = "2024-06-01 14:30:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime localDateTime = LocalDateTime.parse(dateStr, formatter);
String formattedDate = localDateTime.format(formatter);
System.out.println(formattedDate); // 输出: 2024-06-01 14:30:00
-
date和time转换:
Date date = new Date();
LocalDateTime localDateTime = date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
import java.util.Date;
Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
-
数据库种的timestamp和LocaldateTime:
import java.sql.Timestamp;
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
LocalDateTime localDateTime = timestamp.toLocalDateTime();
Timestamp timestamp = Timestamp.valueOf(localDateTime);
// 时区的转换成时间
import java.time.ZonedDateTime;
import java.time.ZoneId;
ZonedDateTime nowInTokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Asia/Shanghai"));
LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
2. 注意点
前端的参数类型名称和请求的header和请求标头和参数的注意
前端可能返回一些空值或者null值或者需要校验的值
在编码时获取到的数据都要像会不会为空,返回的类型会不会匹配
注意返回参数的协调和统一。注意数据为null值时的返回
注意stream流的使用
注意调用工具类中可能的出错点NULL异常和强转异常
类型转换时要注意的:
Transaction transaction = TransactionService.getById(Long.valueOf(request.getWithdrawId()));
注意编码的规范:UTF-8还是GBK还是Unicode或者其他编码
注意时区的统一和注意插入日期时的边界的完整性
3.好用的IDEA的插件
Alibaba Java Coding Guidelines :阿里代码规范插件
Alibaba Cloud AI Coding Assistant 阿里AI助手
CodeGeeX: AL助手,感觉不如上面
TONGYl Lingma 通义灵码
SonarLint
SonarLint 可以帮助在编码时检测代码中的 bug、安全漏洞和代码质量问题,提供实时的静态代码分析功能。
CheckStyle-IDEA
CheckStyle-IDEA 可以帮助检查代码风格是否符合预设的规范,提供代码静态分析功能。
Rainbow Brackets
Rainbow Brackets 可以使括号成对出现时显示不同的颜色,提高代码可读性和编写效率。
JProfiler
JProfiler 是一款性能分析工具,可以帮助分析 Java 应用的性能瓶颈,提供了性能分析和调优的功能。
JRebel for Spring Boot / VisualVM
JRebel for Spring Boot 是针对 Spring Boot 应用的热部署插件,可以加速 Spring Boot 应用的开发和调试过程,提供了实时更新代码的功能。
CoPilot
CoPilot 是 GitHub 推出的一款基于深度学习技术的代码合作者工具,可以为开发者提供智能的代码建议和自动生成代码片段,加速开发流程。