refactor(core):更换jdk17新特性
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package cn.odboy.base;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
@@ -25,5 +26,6 @@ import java.io.Serializable;
|
||||
* @date 2022-01-12
|
||||
*/
|
||||
public class CsObject implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
|
||||
+8
-10
@@ -42,15 +42,13 @@ public class BootApplication {
|
||||
Environment env = application.getEnvironment();
|
||||
String ip = InetAddress.getLocalHost().getHostAddress();
|
||||
String port = env.getProperty("server.port");
|
||||
String path = StrUtil.isEmpty(env.getProperty("config.servlet.context-path")) ?
|
||||
"" :
|
||||
env.getProperty("config.servlet.context-path");
|
||||
log.info(
|
||||
"\n----------------------------------------------------------\n\t" +
|
||||
"Application is running! Access URLs:\n\t" +
|
||||
"Local: \t\thttp://localhost:" + port + path + "/\n\t" +
|
||||
"External: \thttp://" + ip + ":" + port + path + "/\n\t"
|
||||
+ "Swagger文档: \thttp://" + ip + ":" + port + path + "/doc.html\n"
|
||||
+ "----------------------------------------------------------");
|
||||
String path = StrUtil.isEmpty(env.getProperty("config.servlet.context-path")) ? "" : env.getProperty("config.servlet.context-path");
|
||||
log.info("""
|
||||
----------------------------------------------------------
|
||||
\tApplication is running! Access URLs:
|
||||
\tLocal: \t\thttp://localhost:{}{}
|
||||
\tExternal: \thttp://{}:{}{}
|
||||
\tSwagger文档: \thttp://{}:{}{}/doc.html
|
||||
----------------------------------------------------------""", port, path, ip, port, path, ip, port, path);
|
||||
}
|
||||
}
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
///*
|
||||
// * Copyright 2021-2025 Odboy
|
||||
// *
|
||||
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// * you may not use this file except in compliance with the License.
|
||||
// * You may obtain a copy of the License at
|
||||
// *
|
||||
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||
// *
|
||||
// * Unless required by applicable law or agreed to in writing, software
|
||||
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// * See the License for the specific language governing permissions and
|
||||
// * limitations under the License.
|
||||
// */
|
||||
//
|
||||
//package cn.odboy.framework.doc;
|
||||
//
|
||||
//import cn.odboy.framework.properties.AppProperties;
|
||||
//import io.swagger.v3.oas.models.Components;
|
||||
//import io.swagger.v3.oas.models.OpenAPI;
|
||||
//import io.swagger.v3.oas.models.info.Info;
|
||||
//import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||
//import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//
|
||||
///**
|
||||
// * api页面 /doc.html
|
||||
// */
|
||||
//@Configuration
|
||||
//public class SwaggerConfig {
|
||||
// @Autowired
|
||||
// private AppProperties properties;
|
||||
//
|
||||
// @Bean
|
||||
// public OpenAPI customOpenAPI() {
|
||||
// // 添加开关控制
|
||||
// if (!properties.getSwagger().getEnabled()) {
|
||||
// return new OpenAPI();
|
||||
// }
|
||||
// return new OpenAPI().components(new Components().addSecuritySchemes("Authorization",
|
||||
// new SecurityScheme().name("Authorization").type(SecurityScheme.Type.APIKEY).in(SecurityScheme.In.HEADER)))
|
||||
// .info(new Info().title("CuteJava 接口文档").version("1.4.1").description("一个简单且易上手的自动化运维平台"))
|
||||
// .addSecurityItem(new SecurityRequirement().addList("Authorization"));
|
||||
// }
|
||||
//}
|
||||
+2
-2
@@ -76,8 +76,8 @@ public class GlobalExceptionHandler {
|
||||
log.error(ExceptionUtil.stacktraceToString(e));
|
||||
ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
|
||||
String message = objectError.getDefaultMessage();
|
||||
if (objectError instanceof FieldError) {
|
||||
message = ((FieldError) objectError).getField() + ": " + message;
|
||||
if (objectError instanceof FieldError fieldError) {
|
||||
message = fieldError.getField() + ": " + message;
|
||||
}
|
||||
return buildResponseEntity(ApiError.error(message));
|
||||
}
|
||||
|
||||
+21
-57
@@ -33,7 +33,6 @@ import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 查询条件创建工具
|
||||
@@ -78,62 +77,28 @@ public class CsMpQUtil {
|
||||
return StrUtil.toUnderlineCase(attributeName);
|
||||
}
|
||||
|
||||
private static <R> void handleWrapper(
|
||||
CsMpQuery q,
|
||||
QueryWrapper<R> queryWrapper,
|
||||
String attributeName,
|
||||
Object fieldVal) {
|
||||
private static <R> void handleWrapper(CsMpQuery q, QueryWrapper<R> queryWrapper, String attributeName, Object fieldVal) {
|
||||
switch (q.type()) {
|
||||
case EQUAL:
|
||||
queryWrapper.eq(attributeName, fieldVal);
|
||||
break;
|
||||
case GREATER_THAN:
|
||||
queryWrapper.ge(attributeName, fieldVal);
|
||||
break;
|
||||
case LESS_THAN:
|
||||
queryWrapper.le(attributeName, fieldVal);
|
||||
break;
|
||||
case LESS_THAN_NQ:
|
||||
queryWrapper.lt(attributeName, fieldVal);
|
||||
break;
|
||||
case INNER_LIKE:
|
||||
queryWrapper.like(attributeName, fieldVal);
|
||||
break;
|
||||
case LEFT_LIKE:
|
||||
queryWrapper.likeLeft(attributeName, fieldVal);
|
||||
break;
|
||||
case RIGHT_LIKE:
|
||||
queryWrapper.likeRight(attributeName, fieldVal);
|
||||
break;
|
||||
case IN:
|
||||
handleInOrNotQuery(true, queryWrapper, attributeName, fieldVal);
|
||||
break;
|
||||
case NOT_IN:
|
||||
handleInOrNotQuery(false, queryWrapper, attributeName, fieldVal);
|
||||
break;
|
||||
case NOT_EQUAL:
|
||||
queryWrapper.ne(attributeName, fieldVal);
|
||||
break;
|
||||
case NOT_NULL:
|
||||
queryWrapper.isNotNull(attributeName);
|
||||
break;
|
||||
case IS_NULL:
|
||||
queryWrapper.isNull(attributeName);
|
||||
break;
|
||||
case BETWEEN:
|
||||
handleBetweenQuery(queryWrapper, fieldVal, attributeName);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case EQUAL -> queryWrapper.eq(attributeName, fieldVal);
|
||||
case GREATER_THAN -> queryWrapper.ge(attributeName, fieldVal);
|
||||
case LESS_THAN -> queryWrapper.le(attributeName, fieldVal);
|
||||
case LESS_THAN_NQ -> queryWrapper.lt(attributeName, fieldVal);
|
||||
case INNER_LIKE -> queryWrapper.like(attributeName, fieldVal);
|
||||
case LEFT_LIKE -> queryWrapper.likeLeft(attributeName, fieldVal);
|
||||
case RIGHT_LIKE -> queryWrapper.likeRight(attributeName, fieldVal);
|
||||
case IN -> handleInOrNotQuery(true, queryWrapper, attributeName, fieldVal);
|
||||
case NOT_IN -> handleInOrNotQuery(false, queryWrapper, attributeName, fieldVal);
|
||||
case NOT_EQUAL -> queryWrapper.ne(attributeName, fieldVal);
|
||||
case NOT_NULL -> queryWrapper.isNotNull(attributeName);
|
||||
case IS_NULL -> queryWrapper.isNull(attributeName);
|
||||
case BETWEEN -> handleBetweenQuery(queryWrapper, fieldVal, attributeName);
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static <R> void handleInOrNotQuery(
|
||||
boolean b,
|
||||
QueryWrapper<R> queryWrapper,
|
||||
String attributeName,
|
||||
Object fieldVal) {
|
||||
Collection<?> wrapNotInVal = (Collection<?>) fieldVal;
|
||||
private static <R> void handleInOrNotQuery(boolean b, QueryWrapper<R> queryWrapper, String attributeName, Object fieldVal) {
|
||||
Collection<?> wrapNotInVal = (Collection<?>)fieldVal;
|
||||
if (CollectionUtil.isNotEmpty(wrapNotInVal)) {
|
||||
Optional<?> anyValOptional = wrapNotInVal.stream().findAny();
|
||||
if (anyValOptional.isPresent()) {
|
||||
@@ -159,7 +124,7 @@ public class CsMpQUtil {
|
||||
|
||||
private static <R> void handleBetweenQuery(QueryWrapper<R> queryWrapper, Object fieldVal, String finalAttributeName) {
|
||||
if (fieldVal instanceof List) {
|
||||
List<Object> between = new ArrayList<>((List<?>) fieldVal);
|
||||
List<Object> between = new ArrayList<>((List<?>)fieldVal);
|
||||
int minLength = 2;
|
||||
if (CollectionUtil.isNotEmpty(between) && between.size() >= minLength) {
|
||||
queryWrapper.between(finalAttributeName, between.get(0), between.get(1));
|
||||
@@ -180,8 +145,7 @@ public class CsMpQUtil {
|
||||
* @param <R> /
|
||||
*/
|
||||
private static <R> void handleBlurryQuery(QueryWrapper<R> queryWrapper, String blurry, Object fieldVal) {
|
||||
List<String> blurryList =
|
||||
Arrays.stream(blurry.split(",")).filter(StrUtil::isNotBlank).distinct().collect(Collectors.toList());
|
||||
List<String> blurryList = Arrays.stream(blurry.split(",")).filter(StrUtil::isNotBlank).distinct().toList();
|
||||
queryWrapper.and(wrapper -> {
|
||||
for (String blurryItem : blurryList) {
|
||||
String column = StrUtil.toUnderlineCase(blurryItem);
|
||||
@@ -213,7 +177,7 @@ public class CsMpQUtil {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
QueryWrapper<TestDomain> query = new QueryWrapper<TestDomain>();
|
||||
QueryWrapper<TestDomain> query = new QueryWrapper<>();
|
||||
query.or(wrapper -> wrapper.eq("username", 1).or().eq("nickname", 2));
|
||||
query.eq("id", 1);
|
||||
query.orderByDesc("id");
|
||||
|
||||
-1
@@ -34,7 +34,6 @@ public class AppProperties {
|
||||
private ContentRsaEncodeSettingModel rsa;
|
||||
private JwtAuthSettingModel jwt;
|
||||
private UserLoginSettingModel login;
|
||||
private SwaggerApiDocSettingModel swagger;
|
||||
private ThreadPoolSettingModel asyncTaskPool;
|
||||
private CaptchaModel captcha;
|
||||
private StorageOSSModel oss;
|
||||
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021-2025 Odboy
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.odboy.framework.properties.model;
|
||||
|
||||
import cn.odboy.base.CsObject;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author odboy
|
||||
* @date 2025-04-13
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class SwaggerApiDocSettingModel extends CsObject {
|
||||
private Boolean enabled;
|
||||
}
|
||||
+12
-13
@@ -75,30 +75,29 @@ public class UserLoginCaptchaSettingModel extends CsObject {
|
||||
public Captcha getCaptcha() {
|
||||
Captcha captcha;
|
||||
switch (codeType) {
|
||||
case ARITHMETIC:
|
||||
case ARITHMETIC -> {
|
||||
// 算术类型 https://gitee.com/whvse/EasyCaptcha
|
||||
captcha = new FixedArithmeticCaptcha(width, height);
|
||||
// 几位数运算, 默认是两位
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
case CHINESE:
|
||||
}
|
||||
case CHINESE -> {
|
||||
captcha = new ChineseCaptcha(width, height);
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
case CHINESE_GIF:
|
||||
}
|
||||
case CHINESE_GIF -> {
|
||||
captcha = new ChineseGifCaptcha(width, height);
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
case GIF:
|
||||
}
|
||||
case GIF -> {
|
||||
captcha = new GifCaptcha(width, height);
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
case SPEC:
|
||||
}
|
||||
case SPEC -> {
|
||||
captcha = new SpecCaptcha(width, height);
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestException("验证码配置信息错误!正确配置查看 LoginCodeEnum ");
|
||||
}
|
||||
default -> throw new BadRequestException("验证码配置信息错误!正确配置查看 LoginCodeEnum ");
|
||||
}
|
||||
if (StrUtil.isNotBlank(fontName)) {
|
||||
captcha.setFont(new Font(fontName, Font.PLAIN, fontSize));
|
||||
@@ -118,7 +117,7 @@ public class UserLoginCaptchaSettingModel extends CsObject {
|
||||
int opt = num(3);
|
||||
|
||||
// 计算结果
|
||||
int res = new int[]{n1 + n2, n1 - n2, n1 * n2}[opt];
|
||||
int res = new int[] {n1 + n2, n1 - n2, n1 * n2}[opt];
|
||||
// 转换为字符运算符
|
||||
char optChar = "+-x".charAt(opt);
|
||||
|
||||
|
||||
+2
-3
@@ -259,11 +259,10 @@ public class CsRedisHelper {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof List<?>) {
|
||||
List<?> list = (List<?>) value;
|
||||
if (value instanceof List<?> list) {
|
||||
// 检查每个元素是否为指定类型
|
||||
if (list.stream().allMatch(clazz::isInstance)) {
|
||||
return list.stream().map(clazz::cast).collect(Collectors.toList());
|
||||
return list.stream().map(clazz::cast).toList();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
+1
-1
@@ -42,6 +42,6 @@ public class DateStringArraysToListDateConverter implements Converter<String[],
|
||||
} catch (ParseException e) {
|
||||
throw new IllegalArgumentException("Invalid date string: " + s);
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -100,7 +100,7 @@ public class CsWsServer {
|
||||
/**
|
||||
* 精准推送消息
|
||||
*/
|
||||
public void sendMessage(CsWsMessage message, @PathParam("sid") String sid) throws IOException {
|
||||
public void sendMessage(CsWsMessage message, @PathParam("sid") String sid) {
|
||||
String body = JSON.toJSONString(message);
|
||||
// log.info("推送消息到{}, 推送内容:{}", sid, message);
|
||||
try {
|
||||
@@ -138,7 +138,7 @@ public class CsWsServer {
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
CsWsServer that = (CsWsServer) o;
|
||||
CsWsServer that = (CsWsServer)o;
|
||||
return Objects.equals(session, that.session) && Objects.equals(sid, that.sid);
|
||||
}
|
||||
|
||||
|
||||
+6
-18
@@ -61,24 +61,12 @@ public class CsAnonTagUtil {
|
||||
PathPatternsRequestCondition pathPatternsCondition = infoEntry.getKey().getPathPatternsCondition();
|
||||
if (pathPatternsCondition != null) {
|
||||
switch (Objects.requireNonNull(request)) {
|
||||
case GET:
|
||||
get.addAll(pathPatternsCondition.getPatternValues());
|
||||
break;
|
||||
case POST:
|
||||
post.addAll(pathPatternsCondition.getPatternValues());
|
||||
break;
|
||||
case PUT:
|
||||
put.addAll(pathPatternsCondition.getPatternValues());
|
||||
break;
|
||||
case PATCH:
|
||||
patch.addAll(pathPatternsCondition.getPatternValues());
|
||||
break;
|
||||
case DELETE:
|
||||
delete.addAll(pathPatternsCondition.getPatternValues());
|
||||
break;
|
||||
default:
|
||||
all.addAll(pathPatternsCondition.getPatternValues());
|
||||
break;
|
||||
case GET -> get.addAll(pathPatternsCondition.getPatternValues());
|
||||
case POST -> post.addAll(pathPatternsCondition.getPatternValues());
|
||||
case PUT -> put.addAll(pathPatternsCondition.getPatternValues());
|
||||
case PATCH -> patch.addAll(pathPatternsCondition.getPatternValues());
|
||||
case DELETE -> delete.addAll(pathPatternsCondition.getPatternValues());
|
||||
default -> all.addAll(pathPatternsCondition.getPatternValues());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -35,14 +35,14 @@ public final class CsBigDecimalUtil {
|
||||
* @return 转换后的 BigDecimal
|
||||
*/
|
||||
private static BigDecimal toBigDecimal(Object obj) {
|
||||
if (obj instanceof BigDecimal) {
|
||||
return (BigDecimal) obj;
|
||||
} else if (obj instanceof Long) {
|
||||
return BigDecimal.valueOf((Long) obj);
|
||||
} else if (obj instanceof Integer) {
|
||||
return BigDecimal.valueOf((Integer) obj);
|
||||
} else if (obj instanceof Double) {
|
||||
return new BigDecimal(String.valueOf(obj));
|
||||
if (obj instanceof BigDecimal b) {
|
||||
return b;
|
||||
} else if (obj instanceof Long l) {
|
||||
return BigDecimal.valueOf(l);
|
||||
} else if (obj instanceof Integer i) {
|
||||
return BigDecimal.valueOf(i);
|
||||
} else if (obj instanceof Double d) {
|
||||
return new BigDecimal(d);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported type");
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public final class CsCollUtil extends cn.hutool.core.collection.CollUtil {
|
||||
* 使用方式: list = CollUtil.streamDistinct(list, Object::getXXX)
|
||||
*/
|
||||
public static <T, K> List<T> streamDistinct(List<T> data, Function<? super T, ? extends K> keyMapper) {
|
||||
return data.stream().filter(distinctPredicate(keyMapper)).collect(Collectors.toList());
|
||||
return data.stream().filter(distinctPredicate(keyMapper)).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +64,7 @@ public final class CsCollUtil extends cn.hutool.core.collection.CollUtil {
|
||||
public static <T, U extends Comparable<? super U>> List<T> streamAscSort(
|
||||
List<T> data,
|
||||
Function<? super T, ? extends U> keyExtractor) {
|
||||
return data.stream().sorted(Comparator.comparing(keyExtractor)).collect(Collectors.toList());
|
||||
return data.stream().sorted(Comparator.comparing(keyExtractor)).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,7 +81,7 @@ public final class CsCollUtil extends cn.hutool.core.collection.CollUtil {
|
||||
public static <T, U extends Comparable<? super U>> List<T> streamDescSort(
|
||||
List<T> data,
|
||||
Function<? super T, ? extends U> keyExtractor) {
|
||||
return data.stream().sorted(Comparator.comparing(keyExtractor).reversed()).collect(Collectors.toList());
|
||||
return data.stream().sorted(Comparator.comparing(keyExtractor).reversed()).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -91,7 +91,7 @@ public class CsDateUtil {
|
||||
result.append(minutes).append("分");
|
||||
}
|
||||
|
||||
if (seconds > 0 || result.length() == 0) {
|
||||
if (seconds > 0 || result.isEmpty()) {
|
||||
result.append(seconds).append("秒");
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ public class CsDateUtil {
|
||||
}
|
||||
|
||||
// 如果所有单位都是0,则显示0毫秒
|
||||
if (result.length() == 0) {
|
||||
if (result.isEmpty()) {
|
||||
result.append("0毫秒");
|
||||
}
|
||||
|
||||
|
||||
@@ -188,8 +188,7 @@ public final class CsFileUtil extends cn.hutool.core.io.FileUtil {
|
||||
List<Map<String, Object>> sanitizedList = list.parallelStream().map(map -> {
|
||||
Map<String, Object> sanitizedMap = new LinkedHashMap<>();
|
||||
map.forEach((key, value) -> {
|
||||
if (value instanceof String) {
|
||||
String strValue = (String) value;
|
||||
if (value instanceof String strValue) {
|
||||
// 检查并处理以特殊字符开头的值
|
||||
if (strValue.startsWith(SYMBOL_EQUAL) || strValue.startsWith(SYMBOL_ADD) ||
|
||||
strValue.startsWith(SYMBOL_SUBTRACT) || strValue.startsWith(
|
||||
@@ -203,7 +202,7 @@ public final class CsFileUtil extends cn.hutool.core.io.FileUtil {
|
||||
}
|
||||
});
|
||||
return sanitizedMap;
|
||||
}).collect(Collectors.toList());
|
||||
}).toList();
|
||||
// 一次性写出内容, 使用默认样式,强制输出标题
|
||||
writer.write(sanitizedList, true);
|
||||
SXSSFSheet sheet = (SXSSFSheet) writer.getSheet();
|
||||
|
||||
@@ -32,12 +32,12 @@ import java.util.Map;
|
||||
@UtilityClass
|
||||
public final class CsJsonUtil {
|
||||
public static <K, V> Map<K, V> toMap(String jsonStr, Class<K> kClass, Class<V> vClass) {
|
||||
return JSON.parseObject(jsonStr, new TypeReference<Map<K, V>>() {
|
||||
return JSON.parseObject(jsonStr, new TypeReference<>() {
|
||||
});
|
||||
}
|
||||
|
||||
public static <V> List<V> toList(String jsonStr, Class<V> vClass) {
|
||||
return JSON.parseObject(jsonStr, new TypeReference<List<V>>() {
|
||||
return JSON.parseObject(jsonStr, new TypeReference<>() {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -40,12 +40,7 @@ public final class CsListUtil {
|
||||
* @param classifier 对象T属性表达式, 比如: User::getName
|
||||
*/
|
||||
public static <T, K> List<T> distinctByArgs(List<T> items, Function<? super T, ? extends K> classifier) {
|
||||
return items.stream()
|
||||
.collect(Collectors.groupingBy(classifier))
|
||||
.values()
|
||||
.stream()
|
||||
.map(monitorItem -> monitorItem.iterator().next())
|
||||
.collect(Collectors.toList());
|
||||
return items.stream().collect(Collectors.groupingBy(classifier)).values().stream().map(monitorItem -> monitorItem.iterator().next()).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user