一、按行读取文件返回List<String>.
1、java的nio包下使用
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
List<String> list = Files.readAllLines(Paths.get(PATH), StandardCharsets.UTF_8);
2、commons-io下使用
List<String> stringList = FileUtils.readLines(new File(PATH), StandardCharsets.UTF_8);
3、自定义实现
/**
* Buffer读取文件
*/
public static List<String> readFile(){
List<String> list=new ArrayList<>();
try (BufferedReader reader = Files.newBufferedReader(Paths.get(PATH), StandardCharsets.UTF_8)) {
String line;
while ((line = reader.readLine()) != null) {
list.add(line);
}
} catch (IOException e) {
log.error("file read error", e);
}
return list;
}
二、相同List数据叠加.
/**
* List数据叠加
*
* @param baseData 原始结合
* @param addedData 叠加集合
* @return 叠加集合
*/
public static List<Long> add(List<Long> baseData,List<Long> addedData){
if(CollectionUtils.isEmpty(baseData)){
return Collections.emptyList();
}
if(CollectionUtils.isEmpty(addedData)){
return baseData;
}
if(baseData.size()!=addedData.size()){
new GlobalException("base data size not equal added data");
}
for(int i=0;i<baseData.size();i++){
baseData.set(i,baseData.get(i)+addedData.get(i));
}
return baseData;
}
对象判空.
/**
* 对象空判断
*/
public static boolean isEmpty(Object obj) {
if (obj == null) {
return true;
}
if (obj.getClass().isArray()) {
return Array.getLength(obj) == 0;
}
if (obj instanceof CharSequence) {
return ((CharSequence) obj).length() == 0;
}
if (obj instanceof Collection) {
return ((Collection) obj).isEmpty();
}
if (obj instanceof Map) {
return ((Map) obj).isEmpty();
}
// else
return false;
}
三、Long型数据转换int型,注意溢出时候会抛出异常便于排查.
System.out.println(Math.toIntExact(Long.MAX_VALUE));
四、List数组之间转换以及常用的集合工具.
// 1、空集合,底层自定义一个EmptyList实现,接口空list返回,不像new ArrayList分配不必要的内存空间
Collections.emptyList();
// 2、单值List,底层定义SingletonList,size为1
Collections.singletonList(new Object());
// 3、线程安全的List,底层定义SynchronizedList,方法定义通过synchronized代码实现线程安全,定义了一个SynchronizedCollection
Collections.synchronizedList(new ArrayList<>());
// 4、不可变List,不支持修改,定义一个UnmodifiableCollection,UnmodifiableList
Collections.unmodifiableList(new ArrayList<>());
// 5、CopiesList
List<String> stringList = Collections.nCopies(10, "dfs");
// int[]转换List<Integer>
List<Integer> list = Arrays.stream(num).boxed().collect(Collectors.toList());
System.out.println(list);
// list<Integer>转换Integer[]
Integer[] integers = list.stream().toArray(Integer[]::new);
System.out.println(Arrays.toString(integers));
// list<Integer>转换int[]
int[] result = list.stream().mapToInt(Integer::intValue).toArray();
System.out.println(Arrays.toString(result));
// List<Integer>转换Integer[]
Integer[] array = list.toArray(new Integer[0]);
System.out.println(Arrays.toString(array));
// Integer[]转换List<Integer>
List<Integer> asList = Arrays.asList(array);
System.out.println(asList);
// int[]->Integer[]
Integer[] integerNum = Arrays.stream(num).boxed().toArray(Integer[]::new);
// Integer[]->int[]
int[] intNum = Arrays.stream(integerNum).mapToInt(Integer::intValue).toArray();
/**
* Object转换Int
*
* @param value
* @return int
*/
private static int toInt(Object value){
if(value instanceof BigDecimal){
return ((BigDecimal)value).intValue();
}
if(value instanceof BigInteger){
return ((BigInteger)value).intValue();
}
if(value instanceof Integer){
return ((Integer) value).intValue();
}
if(value instanceof Long){
return ((Long)value).intValue();
}
throw new GlobalException("to int error");
}
数组排序,一般使用util包下的以及转换为集合或者是Apache下的包
五、SpringBoot获取初始化ApplicationContext.
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SkywalkApplication.class, args);
// 初始化ApplicationContext
ApplicationContextUtil.setApplicationContext(context);
}
ApplicationContextUtil工具类.
package com.boot.skywalk.bean;
import com.boot.skywalk.exception.GlobalException;
import org.springframework.context.ApplicationContext;
import java.util.Objects;
/**
* ApplicationContext工具类
*/
public final class ApplicationContextUtil {
/**
* 获取ApplicationContext
*/
private static ApplicationContext applicationContext;
private ApplicationContextUtil(){
throw new GlobalException("unsupport create instance!");
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public static void setApplicationContext(ApplicationContext context) {
applicationContext = context;
}
/**
* 获取ApplicationContext
*
* @return ApplicationContext
*/
public static ApplicationContext getInstance(){
if(Objects.isNull(applicationContext)){
new GlobalException("Spring FrameWork Init Failure");
}
return applicationContext;
}
}
六、BeanUtil工具类封装.
package com.boot.skywalk.bean;
import com.boot.skywalk.exception.GlobalException;
import org.apache.commons.collections.MapUtils;
import org.springframework.context.ApplicationContext;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Bean工具获取类
*/
public final class CommonBeanUtils {
private CommonBeanUtils(){
throw new GlobalException("unsupport create instance");
}
/**
* 获取ApplicationContext
*/
private static final ApplicationContext context=ApplicationContextUtil.getInstance();
/**
* 获取指定类型的Bean
*
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> clazz){
return context.getBean(clazz);
}
/**
* 获取指定名称的Bean
*
* @param name
* @return
*/
public static Object getBean(String name) {
return context.getBean(name);
}
/**
* 获取指定类型Bean列表
*
* @param clazz clazz
* @param <T>
* @return List<T>
*/
public static <T> List<T> getBeanList(Class<T> clazz){
Map<String, T> beans = context.getBeansOfType(clazz);
if(MapUtils.isEmpty(beans)){
return Collections.emptyList();
}
List<T> list = beans.values().stream().collect(Collectors.toList());
return list;
}
}
七、Bean的属性复制时候推荐使用Spring框架下的.
①、Spring框架下的BeanUtil
②、Apache下的,有加锁获取逻辑,相对耗时方便推荐Spring框架的.
八、工具类尽可能封装为单例模式,如RestClient、BeanUtils等.
九、当Maven多模块循环依赖时候,经过过滤器需要调用某个类的业务方法时候,这个时候可以使用反射调用.Spring的ReflectUtils或者是Class.forName();
Student student = (Student)ReflectUtils.newInstance(Student.class);
student.test();
十、全局异常定义.
public class GlobalException extends RuntimeException {
public GlobalException() {
super();
}
public GlobalException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
/**
* @param message
* @param cause
*/
public GlobalException(String message, Throwable cause) {
super(message, cause);
}
/**
* @param message
*/
public GlobalException(String message) {
super(message);
}
/**
* @param cause
*/
public GlobalException(Throwable cause) {
super(cause);
}
}
可以根据一些项目自定义一些抽象异常子类,参考Spring框架的.
参数校验使用一些断言更佳.
Assert.isNull(str,"str message");
获取异常堆栈信息.
public static List<Object> getStackInfoList(){
List<Object> list = new ArrayList<>();
try {
int num=1/0;
} catch (Exception e) {
list.add(e.getStackTrace()[0].getClassName());
list.add(e.getStackTrace()[0].getFileName());
list.add(e.getStackTrace()[0].getClass());
list.add(e.getStackTrace()[0].getLineNumber());
}
return list;
}
将异常信息拼接为字符串.
/**
* parse error to string
*
* @param e
* @return
*/
public static String toString(Throwable e) {
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
String errorMsg = stringWriter.toString();
return errorMsg;
}
普通执行器
/**
* 普通执行器
*
* @param supplier
* @param <T>
* @return
*/
public static <T> T executor(Supplier<T> supplier){
return supplier.get();
}
适用一些幂等的Client调用.
import com.boot.skywalk.exception.GlobalException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import java.util.function.Supplier;
/**
* 带重试次数执行器
*
* @param supplier
* @param retry
* @param <T>
* @return
*/
public static <T> T executorWithRetry(Supplier<T> supplier,int retry){
Assert.isTrue(retry>=0, "retry times less than 0");
int times=0;
while(times++<retry){
try {
supplier.get();
} catch (Exception e) {
log.error("service method retry", e);
}
}
log.error("service method already retry times={}",retry);
throw new GlobalException("service method failed");
}
十一、静态块+Map实现一些重构.
1、如一些策略模式缓存策略实现类,StrategyFactory.
private static final Map<String,IStrategy> STRATEGY=new HashMap<>();
十二、函数式接口的封装使用.
1、回调接口.
/**
* 通用回调函数式接口
*/
@FunctionalInterface
public interface ICallback<T>{
/**
* 回调方法
* @param t
*/
void callback(T t);
}
2、参数校验接口.
@FunctionalInterface
public interface ICheck<T> {
/**
* 通用业务校验
* @param t
*/
void check(T t);
}
十三、List指定大小切割.
是直接在原来的List的改变的,partition,guava的也是一样的,一般使用批次更新查询和批次拉取数据,提升性能.
封装一个不改变原来List的partitionList.
/**
* 切割List,类似Lists.partition的切割
*
* @param list
* @param size
* @param <T>
* @return
*/
private static <T> List<List<T>> partition(List<T> list, int size){
if(CollectionUtils.isEmpty(list)){
throw new GlobalException("partition list is null");
}
if(size<0){
throw new GlobalException("partition size less than 0");
}
int length=list.size();
// 计算分组大小
int partitionSize=(length+size-1)/size;
List<List<T>> newList = new ArrayList<>(partitionSize);
for(int i=0;i<partitionSize;i++){
int fromIndex=i*size;
int toIndex=Math.min((i+1)*size,length);
newList.add(list.subList(fromIndex, toIndex));
}
return newList;
}
使用方式如下:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, -6, 7, 8, 9, 10, -11, 12, 13, -14, 15, 16);
// 分组
List<List<Integer>> partitionList = partition(list, 5);
System.out.println(partitionList);
List<List<Integer>> result=new ArrayList<>();
// 分组后再过滤
partitionList.stream().forEach(partition->{
List<Integer> collect = partition.stream().filter(num -> num > 0).collect(Collectors.toList());
result.add(collect);
});
System.out.println(result);
// 过滤再分组
List<Integer> filterList = list.stream().filter(num -> num > 0).collect(Collectors.toList());
List<List<Integer>> partitionResultList = partition(filterList, 5);
System.out.println(partitionResultList);
不同的判定逻辑,注意业务代码中的使用.
十三、时间工具类,参考Flink工具类封装.
org.apache.flink.api.common.time
public final class Time implements Serializable {
private static final long serialVersionUID = -350254188460915999L;
/** The time unit for this policy's time interval. */
private final TimeUnit unit;
/** The size of the windows generated by this policy. */
private final long size;
/** Instantiation only via factory method. */
private Time(long size, TimeUnit unit) {
this.unit = checkNotNull(unit, "time unit may not be null");
this.size = size;
}
// ------------------------------------------------------------------------
// Properties
// ------------------------------------------------------------------------
/**
* Gets the time unit for this policy's time interval.
*
* @return The time unit for this policy's time interval.
*/
public TimeUnit getUnit() {
return unit;
}
/**
* Gets the length of this policy's time interval.
*
* @return The length of this policy's time interval.
*/
public long getSize() {
return size;
}
/**
* Converts the time interval to milliseconds.
*
* @return The time interval in milliseconds.
*/
public long toMilliseconds() {
return unit.toMillis(size);
}
@Override
public String toString() {
return toMilliseconds() + " ms";
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Time time = (Time) o;
return toMilliseconds() == time.toMilliseconds();
}
@Override
public int hashCode() {
return Objects.hash(toMilliseconds());
}
// ------------------------------------------------------------------------
// Factory
// ------------------------------------------------------------------------
/**
* Creates a new {@link Time} of the given duration and {@link TimeUnit}.
*
* @param size The duration of time.
* @param unit The unit of time of the duration, for example {@code TimeUnit.SECONDS}.
* @return The time policy.
*/
public static Time of(long size, TimeUnit unit) {
return new Time(size, unit);
}
/** Creates a new {@link Time} that represents the given number of milliseconds. */
public static Time milliseconds(long milliseconds) {
return of(milliseconds, TimeUnit.MILLISECONDS);
}
/** Creates a new {@link Time} that represents the given number of seconds. */
public static Time seconds(long seconds) {
return of(seconds, TimeUnit.SECONDS);
}
/** Creates a new {@link Time} that represents the given number of minutes. */
public static Time minutes(long minutes) {
return of(minutes, TimeUnit.MINUTES);
}
/** Creates a new {@link Time} that represents the given number of hours. */
public static Time hours(long hours) {
return of(hours, TimeUnit.HOURS);
}
/** Creates a new {@link Time} that represents the given number of days. */
public static Time days(long days) {
return of(days, TimeUnit.DAYS);
}
/**
* Creates a new {@link Time} that represents the number of milliseconds in the given duration.
*/
public static Time fromDuration(Duration duration) {
return milliseconds(duration.toMillis());
}
}
十四、线程休眠工具类,封装逻辑.
线程休眠方式.
// 原生线程休眠
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
并发工具包休眠方式
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
import com.boot.skywalk.exception.GlobalException;
import lombok.extern.slf4j.Slf4j;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* 线程工具类封装,ThreadUtil
*/
@Slf4j
public final class ThreadUtil {
/**
* Number of milliseconds in a standard second.
*/
public static final long MILLIS_PER_SECOND = 1000;
/**
* Number of milliseconds in a standard minute.
*/
public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
/**
* Number of milliseconds in a standard hour.
*/
public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
/**
* Number of milliseconds in a standard day.
*/
public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
/**
* 校验时间单位
*
* @param duration duration
* @param unit unit
*/
public static void checkDurationLength(long duration, TimeUnit unit){
long durationSeconds = TimeUnit.MILLISECONDS.convert(duration, unit);
if(durationSeconds<0||durationSeconds>MILLIS_PER_DAY){
log.error("illegal duration time,duration={},unit={}",duration,unit);
throw new GlobalException("duration time is illegal");
}
}
/**
* 毫秒级中断线程
*
* @param millSeconds
*/
public static void pauseThreadMillSeconds(long millSeconds){
pauseThread(millSeconds, TimeUnit.MILLISECONDS);
}
/**
* 秒级中断线程
*
* @param seconds
*/
public static void pauseThreadSeconds(long seconds){
pauseThread(seconds, TimeUnit.SECONDS);
}
/**
* 中断线程
*
* @param duration duration
* @param unit unit
*/
public static void pauseThread(long duration,TimeUnit unit){
if(Objects.isNull(unit)){
log.error("TimeUnit is null");
throw new GlobalException("TimeUnit is null");
}
checkDurationLength(duration, unit);
try {
unit.sleep(duration);
} catch (InterruptedException e) {
log.error("pause thread fail,duration={},unit={}",duration,unit,e);
}
}
// 使用
public static void main(String[] args) {
System.out.println("start");
pauseThreadSeconds(10);
System.out.println("end");
}
}
Spring框架反射工具类使用:
一般在Maven多模块调用解决循环依赖的时候可以通过反射调用即可.
package com.boot.skywalk.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* ReflectTest.
*/
@Slf4j
public class ReflectTest {
/**
* Reflect CLASS
*/
private static final String MAP_CLASS="com.boot.skywalk.util.MapUtil";
public static void main(String[] args) {
Class<?> forName=null;
try {
forName=Class.forName(MAP_CLASS);
} catch (ClassNotFoundException e) {
log.error("reflect class error!", e);
}
Map<String,String> map=new HashMap<>();
map.put("Single","Single-Value");
// 反射调用
Method method = ReflectionUtils.findMethod(forName, "getMap", Map.class);
Map<String,String> resp=null;
try {
resp=(Map<String,String>)method.invoke(null, map);
} catch (IllegalAccessException e) {
log.error("IllegalAccessException",e);
} catch (InvocationTargetException e) {
log.error("InvocationTargetException",e);
}
System.out.println(resp);
}
}
源码介绍:
public static Method findMethod(Class<?> clazz, String name, @Nullable Class<?>... paramTypes) {
Assert.notNull(clazz, "Class must not be null");
Assert.notNull(name, "Method name must not be null");
Class<?> searchType = clazz;
while (searchType != null) {
Method[] methods = (searchType.isInterface() ? searchType.getMethods() :
getDeclaredMethods(searchType, false));
for (Method method : methods) {
if (name.equals(method.getName()) && (paramTypes == null || hasSameParams(method, paramTypes))) {
return method;
}
}
searchType = searchType.getSuperclass();
}
return null;
}
MyBatisPlus的反射工具类:
ReflectionKit工具类介绍:
package com.baomidou.mybatisplus.core.toolkit;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toMap;
/**
* <p>
* 反射工具类
* </p>
*
* @author Caratacus
* @since 2016-09-22
*/
public class ReflectionKit {
private static final Log logger = LogFactory.getLog(ReflectionKit.class);
/**
* class field cache
*/
private static final Map<Class<?>, List<Field>> CLASS_FIELD_CACHE = new ConcurrentHashMap<>();
private static final Map<Class<?>, Class<?>> PRIMITIVE_WRAPPER_TYPE_MAP = new IdentityHashMap<>(8);
static {
PRIMITIVE_WRAPPER_TYPE_MAP.put(Boolean.class, boolean.class);
PRIMITIVE_WRAPPER_TYPE_MAP.put(Byte.class, byte.class);
PRIMITIVE_WRAPPER_TYPE_MAP.put(Character.class, char.class);
PRIMITIVE_WRAPPER_TYPE_MAP.put(Double.class, double.class);
PRIMITIVE_WRAPPER_TYPE_MAP.put(Float.class, float.class);
PRIMITIVE_WRAPPER_TYPE_MAP.put(Integer.class, int.class);
PRIMITIVE_WRAPPER_TYPE_MAP.put(Long.class, long.class);
PRIMITIVE_WRAPPER_TYPE_MAP.put(Short.class, short.class);
}
/**
* <p>
* 反射 method 方法名,例如 getId
* </p>
*
* @param field
* @param str 属性字符串内容
*/
public static String getMethodCapitalize(Field field, final String str) {
Class<?> fieldType = field.getType();
// fix #176
return StringUtils.concatCapitalize(boolean.class.equals(fieldType) ? "is" : "get", str);
}
/**
* <p>
* 反射 method 方法名,例如 setVersion
* </p>
*
* @param field Field
* @param str String JavaBean类的version属性名
* @return version属性的setter方法名称,e.g. setVersion
* @deprecated 3.0.8
*/
@Deprecated
public static String setMethodCapitalize(Field field, final String str) {
return StringUtils.concatCapitalize("set", str);
}
/**
* <p>
* 获取 public get方法的值
* </p>
*
* @param cls ignore
* @param entity 实体
* @param str 属性字符串内容
* @return Object
*/
public static Object getMethodValue(Class<?> cls, Object entity, String str) {
Map<String, Field> fieldMaps = getFieldMap(cls);
try {
Assert.notEmpty(fieldMaps, "Error: NoSuchField in %s for %s. Cause:", cls.getSimpleName(), str);
Method method = cls.getMethod(getMethodCapitalize(fieldMaps.get(str), str));
return method.invoke(entity);
} catch (NoSuchMethodException e) {
throw ExceptionUtils.mpe("Error: NoSuchMethod in %s. Cause:", e, cls.getSimpleName());
} catch (IllegalAccessException e) {
throw ExceptionUtils.mpe("Error: Cannot execute a private method. in %s. Cause:", e, cls.getSimpleName());
} catch (InvocationTargetException e) {
throw ExceptionUtils.mpe("Error: InvocationTargetException on getMethodValue. Cause:" + e);
}
}
/**
* <p>
* 获取 public get方法的值
* </p>
*
* @param entity 实体
* @param str 属性字符串内容
* @return Object
*/
public static Object getMethodValue(Object entity, String str) {
if (null == entity) {
return null;
}
return getMethodValue(entity.getClass(), entity, str);
}
/**
* <p>
* 反射对象获取泛型
* </p>
*
* @param clazz 对象
* @param index 泛型所在位置
* @return Class
*/
public static Class<?> getSuperClassGenericType(final Class<?> clazz, final int index) {
Type genType = clazz.getGenericSuperclass();
if (!(genType instanceof ParameterizedType)) {
logger.warn(String.format("Warn: %s's superclass not ParameterizedType", clazz.getSimpleName()));
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0) {
logger.warn(String.format("Warn: Index: %s, Size of %s's Parameterized Type: %s .", index,
clazz.getSimpleName(), params.length));
return Object.class;
}
if (!(params[index] instanceof Class)) {
logger.warn(String.format("Warn: %s not set the actual class on superclass generic parameter",
clazz.getSimpleName()));
return Object.class;
}
return (Class<?>) params[index];
}
/**
* <p>
* 获取该类的所有属性列表
* </p>
*
* @param clazz 反射类
*/
public static Map<String, Field> getFieldMap(Class<?> clazz) {
List<Field> fieldList = getFieldList(clazz);
return CollectionUtils.isNotEmpty(fieldList) ? fieldList.stream().collect(Collectors.toMap(Field::getName, field -> field)) : Collections.emptyMap();
}
/**
* <p>
* 获取该类的所有属性列表
* </p>
*
* @param clazz 反射类
*/
public static List<Field> getFieldList(Class<?> clazz) {
if (Objects.isNull(clazz)) {
return Collections.emptyList();
}
List<Field> fields = CLASS_FIELD_CACHE.get(clazz);
if (CollectionUtils.isEmpty(fields)) {
synchronized (CLASS_FIELD_CACHE) {
fields = doGetFieldList(clazz);
CLASS_FIELD_CACHE.put(clazz, fields);
}
}
return fields;
}
/**
* <p>
* 获取该类的所有属性列表
* </p>
*
* @param clazz 反射类
*/
public static List<Field> doGetFieldList(Class<?> clazz) {
if (clazz.getSuperclass() != null) {
/* 排除重载属性 */
Map<String, Field> fieldMap = excludeOverrideSuperField(clazz.getDeclaredFields(),
/* 处理父类字段 */
getFieldList(clazz.getSuperclass()));
List<Field> fieldList = new ArrayList<>();
/*
* 重写父类属性过滤后处理忽略部分,支持过滤父类属性功能
* 场景:中间表不需要记录创建时间,忽略父类 createTime 公共属性
* 中间表实体重写父类属性 ` private transient Date createTime; `
*/
fieldMap.forEach((k, v) -> {
/* 过滤静态属性 */
if (!Modifier.isStatic(v.getModifiers())
/* 过滤 transient关键字修饰的属性 */
&& !Modifier.isTransient(v.getModifiers())) {
fieldList.add(v);
}
});
return fieldList;
} else {
return Collections.emptyList();
}
}
/**
* <p>
* 排序重置父类属性
* </p>
*
* @param fields 子类属性
* @param superFieldList 父类属性
*/
public static Map<String, Field> excludeOverrideSuperField(Field[] fields, List<Field> superFieldList) {
// 子类属性
Map<String, Field> fieldMap = Stream.of(fields).collect(toMap(Field::getName, identity()));
superFieldList.stream().filter(field -> !fieldMap.containsKey(field.getName()))
.forEach(f -> fieldMap.put(f.getName(), f));
return fieldMap;
}
/**
* 获取字段get方法
*
* @param cls class
* @param field 字段
* @return Get方法
*/
public static Method getMethod(Class<?> cls, Field field) {
try {
return cls.getDeclaredMethod(ReflectionKit.getMethodCapitalize(field, field.getName()));
} catch (NoSuchMethodException e) {
throw ExceptionUtils.mpe("Error: NoSuchMethod in %s. Cause:", e, cls.getName());
}
}
/**
* 判断是否为基本类型或基本包装类型
*
* @param clazz class
* @return 是否基本类型或基本包装类型
*/
public static boolean isPrimitiveOrWrapper(Class<?> clazz) {
Assert.notNull(clazz, "Class must not be null");
return (clazz.isPrimitive() || PRIMITIVE_WRAPPER_TYPE_MAP.containsKey(clazz));
}
}
List<Field> fieldList = ReflectionKit.getFieldList(ReflectTest.class);
System.out.println(fieldList);
异常堆栈信息打印:
package com.boot.skywalk.vo;
import java.util.LinkedHashMap;
import java.util.Map;
public class ExceptionUtil {
public static void main(String[] args) {
try{
int num=1/0;
}catch (ArithmeticException e){
System.out.println(recordExceptionMap(e));
}
}
/**
* 记录Exception堆栈信息
*
* @param exception
* @return Map<String,Object>
*/
public static Map<String,Object> recordExceptionMap(Exception exception){
Map<String,Object> map=new LinkedHashMap<>();
StackTraceElement stackTraceElement = exception.getStackTrace()[0];
map.put("class_name",stackTraceElement.getClassName());
map.put("file_name",stackTraceElement.getFileName());
map.put("method_name",stackTraceElement.getMethodName());
map.put("line_number",stackTraceElement.getLineNumber());
return map;
}
}
Stream的静态方法,流的特点:无法重复消费、不存放数据、不改变数据源,具有延迟性,只有终端执行操作了,中间才会执行.
// Stream的静态方法
Stream<Integer> stream0 = Stream.of(7, 8, 9, 10, 11);
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6);
// 合并流
Stream<Integer> concatStream = Stream.concat(stream0, stream1);
concatStream.forEach(System.out::println);
// 迭代无限流
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
stream2.forEach(System.out::println);
// 生产无限流
Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
stream3.forEach(System.out::println);
Java8 Stream:2万字20个实例,玩转集合的筛选、归约、分组、聚合
分区和分组区别:主要是看函数式接口,Function和Predicate
public static <T>
Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
return partitioningBy(predicate, toList());
}
public static <T, K, A, D>
Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream) {
return groupingBy(classifier, HashMap::new, downstream);
}
常用总结:
toMap-->stream转为map
Function.identity()-->返回stream中的元素
集合-->Stream:stream()
数组-->Stream:Stream.of(T t)或者Arrays.stream(T[] t)
任意元素-->Stream:Stream.of(T... values)
归约:是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。
获取字符串最大长度
public static void getMaxStr(){
List<String> list = Arrays.asList("abb", "abcd", "fegc", "efe", "adfes");
// 最长字符串长度
int maxLength = list.stream().filter(s -> s.startsWith("a")).mapToInt(r -> r.length()).max().orElse(0);
System.out.println(maxLength);
// 最长字符串
Optional<String> optional = list.stream().filter(s -> s.startsWith("a")).max(Comparator.comparing(String::length));
String string = Optional.ofNullable(optional.get()).orElse("");
System.out.println(string);
}
对象属性求和
/**
* Stream计算属性和
* @return int
*/
public static int getSum(){
Student s1 = new Student("张一",5);
Student s2 = new Student("张二",3);
Student s3 = new Student("张三",4);
Student s4 = new Student("张四",1);
List<Student> list=new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
// 计算属性和:返回一个IntStream其中包含给定函数应用于此流得元素的结果
int sum = list.stream().mapToInt(o -> Objects.isNull(o.getAge()) ? 0 : o.getAge()).sum();
List<Integer> ageList = list.stream().map(o -> Objects.isNull(o.getAge()) ? 0 : o.getAge()).collect(Collectors.toList());
// reduce规约计算
Optional<Integer> result = ageList.stream().reduce(Integer::sum);
System.out.println(result.get());
return sum;
}
BIO流读取:
①、字节流读取
/**
* 通过字节流实现文件复制:FileInputStream/FileOutputStream
*/
public static void writeByInputStream(){
//使用 jdk7 引入的自动关闭资源的 try 语句(该资源类要实现 AutoCloseable 或 Closeable 接口)
try (FileInputStream fis = new FileInputStream("D:\\红色电视剧.txt");
FileOutputStream fos = new FileOutputStream("D:\\红色电视剧_copy.txt")) {
byte[] buf = new byte[126];
int hasRead = 0;
while ((hasRead = fis.read(buf)) > 0) {
//每次读取多少就写多少
fos.write(buf, 0, hasRead);
}
} catch (Exception e) {
log.error("write error", e);
}
}
②、字符流读取
/**
* 通过字符流读取:FileReader/FileWriter
*/
public static void writeByReader(){
//使用 jdk7 引入的自动关闭资源的 try 语句
try (FileReader fr = new FileReader("D:\\红色电视剧.txt");
FileWriter fw = new FileWriter("D:\\红色电视剧_copy1.txt")) {
char[] buf = new char[126];
int hasRead = 0;
while ((hasRead = fr.read(buf)) > 0) {
//每次读取多少就写多少
fw.write(buf, 0, hasRead);
}
} catch (Exception e){
log.error("write error", e);
}
}
③、字符缓存流,按照行读取
/**
* 通过字符缓存流读取:BufferedReader/BufferedWriter
*/
public static void writeByBufferReader(){
//使用普通的 Reader 不方便整行读取,可以使用 BufferReader 包装,资源变量要定义在 try()中,否则不会自动关闭
try (FileReader fr = new FileReader("D:\\红色电视剧.txt");
FileWriter fw = new FileWriter("D:\\红色电视剧_copy2.txt");
// 装饰缓存流
BufferedReader bufferedReader = new BufferedReader(fr);
BufferedWriter bufferedWriter = new BufferedWriter(fw)) {
String line;
while ((line = bufferedReader.readLine()) != null) {
//每次读取一行、写入一行
bufferedWriter.write(line);
bufferedWriter.newLine();
}
} catch (Exception e) {
log.error("write error", e);
}
}
Bean和Map的工具类封装,基于cglib包实现.
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.3.0</version>
</dependency>
Mybatis-Plus框架封装BeanUtils工具类
package com.baomidou.mybatisplus.core.toolkit;
import static java.util.stream.Collectors.toList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import net.sf.cglib.beans.BeanMap;
/**
* Bean 转换工具类
* <p>使用请依赖 cglib 包</p>
*
* @author hubin HCL
* @since 2018-06-12
*/
public final class BeanUtils {
private BeanUtils() {
}
/**
* 将对象装换为 map,对象转成 map,key肯定是字符串
*
* @param bean 转换对象
* @return 返回转换后的 map 对象
*/
@SuppressWarnings("unchecked")
public static Map<String, Object> beanToMap(Object bean) {
return null == bean ? null : BeanMap.create(bean);
}
/**
* map 装换为 java bean 对象
*
* @param map 转换 MAP
* @param clazz 对象 Class
* @return 返回 bean 对象
*/
public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) {
T bean = ClassUtils.newInstance(clazz);
BeanMap.create(bean).putAll(map);
return bean;
}
/**
* List<T> 转换为 List<Map<String, Object>>
*
* @param beans 转换对象集合
* @return 返回转换后的 bean 列表
*/
public static <T> List<Map<String, Object>> beansToMaps(List<T> beans) {
if (CollectionUtils.isEmpty(beans)) {
return Collections.emptyList();
}
return beans.stream().map(BeanUtils::beanToMap).collect(toList());
}
/**
* List<Map<String, Object>> 转换为 List<T>
*
* @param maps 转换 MAP 集合
* @param clazz 对象 Class
* @return 返回转换后的 bean 集合
*/
public static <T> List<T> mapsToBeans(List<Map<String, Object>> maps, Class<T> clazz) {
if (CollectionUtils.isEmpty(maps)) {
return Collections.emptyList();
}
return maps.stream().map(e -> mapToBean(e, clazz)).collect(toList());
}
}
测试一下工具:
/**
* 测试Bean转换Map
* @return Map<String, Object>
*/
public static Map<String, Object> beanToMapTest(){
Student s1 = new Student("张一",5);
Map<String, Object> map = beanToMap(s1);
return map;
}
/**
* 测试List<Bean>转换List<Map>
* @return Map<String, Object>
*/
public static List<Map<String, Object>> beanListToMapTest(){
Student s1 = new Student("张一",5);
Student s2 = new Student("张二",4);
Student s3 = new Student("张三",3);
Student s4 = new Student("张四",2);
Student s5 = new Student(null,1);
List<Student> list=new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
list.add(s5);
List<Map<String, Object>> maps = beansToMaps(list);
return maps;
}
public static void main(String[] args) {
Map<String, Object> map = beanToMapTest();
System.out.println("Bean转换Map:"+map);
Student student = mapToBean(map, Student.class);
System.out.println("Map转换Bean"+student);
List<Map<String, Object>> list = beanListToMapTest();
System.out.println("ListBean转换ListMap"+list);
List<Student> studentList = mapsToBeans(list, Student.class);
System.out.println("ListMap转换ListBean"+studentList);
}
十五、并发测试工具类
1、开源的HuTool测试工具类.
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.8.6</version>
</dependency>
package com.boot.skywalk;
import cn.hutool.core.thread.ConcurrencyTester;
import cn.hutool.core.thread.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* Hutool并发工具类测试
*/
@Slf4j
public class ConcurrentTest {
private static final Map<String, List<Integer>> MAP = new HashMap<>();
private static final Map<String, List<Integer>> CONCURRENTHASH_MAP = new ConcurrentHashMap<>();
public static void main(String[] args) throws IOException {
// 1、定义多少个线程,这里是100个并发,每个执行业务逻辑是循环计算
ConcurrencyTester concurrencyTester = ThreadUtil.concurrencyTest(100, new Runnable() {
@Override
public void run() {
List<Integer> list = IntStream.range(1, 1001).boxed().collect(Collectors.toList());
for(int i=0;i<100;i++){
MAP.put(Thread.currentThread().getName()+"-"+i, list);
CONCURRENTHASH_MAP.put(Thread.currentThread().getName()+"-"+i, list);
}
}
});
//MAP.forEach((key, value) -> {
// log.info("key={},value={}", key, value);
//});
log.info("total HashMap size={},ConcurrentHashMap size={}",MAP.size(),CONCURRENTHASH_MAP.size());
log.info("total cost time={}", concurrencyTester.getInterval()+"ms");
// 2、关闭
concurrencyTester.close();
}
}
同时验证HashMap是线程不安全的.
源码也是比较简单的,ExecutorService+CountDownLatch
package cn.hutool.core.thread;
import cn.hutool.core.exceptions.UtilException;
import java.io.Closeable;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
/**
* 线程同步结束器<br>
* 在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
*
* <pre>
* ps:
* //模拟1000个线程并发
* SyncFinisher sf = new SyncFinisher(1000);
* sf.addWorker(() -> {
* // 需要并发测试的业务代码
* });
* sf.start()
* </pre>
*
*
* @author Looly
* @since 4.1.15
*/
public class SyncFinisher implements Closeable {
private final Set<Worker> workers;
private final int threadSize;
private ExecutorService executorService;
private boolean isBeginAtSameTime;
/** 启动同步器,用于保证所有worker线程同时开始 */
private final CountDownLatch beginLatch;
/** 结束同步器,用于等待所有worker线程同时结束 */
private CountDownLatch endLatch;
/**
* 构造
*
* @param threadSize 线程数
*/
public SyncFinisher(int threadSize) {
this.beginLatch = new CountDownLatch(1);
this.threadSize = threadSize;
this.workers = new LinkedHashSet<>();
}
/**
* 设置是否所有worker线程同时开始
*
* @param isBeginAtSameTime 是否所有worker线程同时开始
* @return this
*/
public SyncFinisher setBeginAtSameTime(boolean isBeginAtSameTime) {
this.isBeginAtSameTime = isBeginAtSameTime;
return this;
}
/**
* 增加定义的线程数同等数量的worker
*
* @param runnable 工作线程
* @return this
*/
public SyncFinisher addRepeatWorker(final Runnable runnable) {
for (int i = 0; i < this.threadSize; i++) {
addWorker(new Worker() {
@Override
public void work() {
runnable.run();
}
});
}
return this;
}
/**
* 增加工作线程
*
* @param runnable 工作线程
* @return this
*/
public SyncFinisher addWorker(final Runnable runnable) {
return addWorker(new Worker() {
@Override
public void work() {
runnable.run();
}
});
}
/**
* 增加工作线程
*
* @param worker 工作线程
* @return this
*/
synchronized public SyncFinisher addWorker(Worker worker) {
workers.add(worker);
return this;
}
/**
* 开始工作<br>
* 执行此方法后如果不再重复使用此对象,需调用{@link #stop()}关闭回收资源。
*/
public void start() {
start(true);
}
/**
* 开始工作<br>
* 执行此方法后如果不再重复使用此对象,需调用{@link #stop()}关闭回收资源。
*
* @param sync 是否阻塞等待
* @since 4.5.8
*/
public void start(boolean sync) {
endLatch = new CountDownLatch(workers.size());
if(null == this.executorService || this.executorService.isShutdown()){
this.executorService = ThreadUtil.newExecutor(threadSize);
}
for (Worker worker : workers) {
executorService.submit(worker);
}
// 保证所有worker同时开始
this.beginLatch.countDown();
if (sync) {
try {
this.endLatch.await();
} catch (InterruptedException e) {
throw new UtilException(e);
}
}
}
/**
* 结束线程池。此方法执行两种情况:
* <ol>
* <li>执行start(true)后,调用此方法结束线程池回收资源</li>
* <li>执行start(false)后,用户自行判断结束点执行此方法</li>
* </ol>
*
* @since 5.6.6
*/
public void stop(){
if(null != this.executorService){
this.executorService.shutdown();
}
this.executorService = null;
clearWorker();
}
/**
* 清空工作线程对象
*/
public void clearWorker() {
workers.clear();
}
/**
* 剩余任务数
*
* @return 剩余任务数
*/
public long count() {
return endLatch.getCount();
}
@Override
public void close() throws IOException {
stop();
}
/**
* 工作者,为一个线程
*
* @author xiaoleilu
*
*/
public abstract class Worker implements Runnable {
@Override
public void run() {
if (isBeginAtSameTime) {
try {
beginLatch.await();
} catch (InterruptedException e) {
throw new UtilException(e);
}
}
try {
work();
} finally {
endLatch.countDown();
}
}
/**
* 任务内容
*/
public abstract void work();
}
}
2、自定义
public static void concurrencyTest(){
concurrencyExecute(100, ()->{
List<Integer> list = IntStream.range(1, 1001).boxed().collect(Collectors.toList());
for(int i=0;i<100;i++){
MAP.put(Thread.currentThread().getName()+"-"+i, list);
CONCURRENTHASH_MAP.put(Thread.currentThread().getName()+"-"+i, list);
}
return null;
});
log.info("total HashMap size={},ConcurrentHashMap size={}",MAP.size(),CONCURRENTHASH_MAP.size());
}
public static <T> T concurrencyExecute(int threadNumber, Supplier<T> supplier) {
CountDownLatch start = new CountDownLatch(1);
CountDownLatch end = new CountDownLatch(threadNumber);
ExecutorService executorService = Executors.newFixedThreadPool(threadNumber);
T object = null;
for (int i = 0; i < threadNumber; i++) {
executorService.submit(() -> {
try {
// 1、先阻塞这别让这个线程跑起来
start.await();
// 具体的业务方法(本地方法 or 远程调用)
supplier.get();
} catch (InterruptedException e) {
log.error("error message",e);
Thread.currentThread().interrupt();
} finally {
// 一个线程跑完 end计数器-1
end.countDown();
}
});
}
// start-1 所有线程启动,同时进行业务计算
start.countDown();
// 阻塞直到所有线程执行完毕
try {
end.await();
} catch (InterruptedException e) {
log.error("error message",e);
Thread.currentThread().interrupt();
}
executorService.shutdown();
return object;
}
十六、MyBatis的防止SQL注入写法.
1、in查询写法
错误写法:不是用$替换
Select * from news where id in (#{ids})
正确写法:
<!-- in查询写法-->
<select id="queryListByIds" resultType="com.boot.skywalk.entity.UserInfo">
SELECT * from user_info where create_time>#{createTime} and id in
<foreach collection="list" item="idItem" open="(" close=")" separator="," >
#{idItem}
</foreach>
</select>
2、like模糊查询写法
错误写法:
Select * from news where title like ‘%#{title}%’
正确写法:
<!--左匹配和右匹配 -->
<!-- select * from user_info where user_name like concat('%',#{userName},'%')-->
<select id="queryListByUserName" resultType="com.boot.skywalk.entity.UserInfo">
select * from user_info where user_name like concat(#{userName},'%')
</select>
借助ConcurrentHashMap封装一个ConcurrentHashSet.参考Dubbo的实现.
package org.apache.dubbo.common.utils;
import java.util.AbstractSet;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class ConcurrentHashSet<E> extends AbstractSet<E> implements Set<E>, java.io.Serializable {
private static final long serialVersionUID = -8672117787651310382L;
private static final Object PRESENT = new Object();
private final ConcurrentMap<E, Object> map;
public ConcurrentHashSet() {
map = new ConcurrentHashMap<E, Object>();
}
public ConcurrentHashSet(int initialCapacity) {
map = new ConcurrentHashMap<E, Object>(initialCapacity);
}
/**
* Returns an iterator over the elements in this set. The elements are
* returned in no particular order.
*
* @return an Iterator over the elements in this set
* @see ConcurrentModificationException
*/
@Override
public Iterator<E> iterator() {
return map.keySet().iterator();
}
/**
* Returns the number of elements in this set (its cardinality).
*
* @return the number of elements in this set (its cardinality)
*/
@Override
public int size() {
return map.size();
}
/**
* Returns <tt>true</tt> if this set contains no elements.
*
* @return <tt>true</tt> if this set contains no elements
*/
@Override
public boolean isEmpty() {
return map.isEmpty();
}
/**
* Returns <tt>true</tt> if this set contains the specified element. More
* formally, returns <tt>true</tt> if and only if this set contains an
* element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>.
*
* @param o element whose presence in this set is to be tested
* @return <tt>true</tt> if this set contains the specified element
*/
@Override
public boolean contains(Object o) {
return map.containsKey(o);
}
/**
* Adds the specified element to this set if it is not already present. More
* formally, adds the specified element <tt>e</tt> to this set if this set
* contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>. If this
* set already contains the element, the call leaves the set unchanged and
* returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
@Override
public boolean add(E e) {
return map.put(e, PRESENT) == null;
}
/**
* Removes the specified element from this set if it is present. More
* formally, removes an element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>, if this
* set contains such an element. Returns <tt>true</tt> if this set contained
* the element (or equivalently, if this set changed as a result of the
* call). (This set will not contain the element once the call returns.)
*
* @param o object to be removed from this set, if present
* @return <tt>true</tt> if the set contained the specified element
*/
@Override
public boolean remove(Object o) {
return map.remove(o) == PRESENT;
}
/**
* Removes all of the elements from this set. The set will be empty after
* this call returns.
*/
@Override
public void clear() {
map.clear();
}
}
十七、时间格式转换
yyyy-MM-dd'T'HH:mm:ss.SSSXXX转换yyyy-MM-dd HH:mm:ss
yyyy-MM-dd'T'HH:mm:ss.SSSZ转换yyyy-MM-dd HH:mm:ss
/**
* 时间转换Z表示时区,RFC 822时区
* @param date
* @return
*/
private static String formateUtcRfc(Date date){
String format="yyyy-MM-dd'T'HH:mm:ss.SSSZ";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
String result = simpleDateFormat.format(date);
System.out.println(result);
return result;
}
/**
* 时间转换Z表示时区,ISO 8601时区
* @param date
* @return
*/
private static String formateUtcIso(Date date){
String format="yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
String result = simpleDateFormat.format(date);
System.out.println(result);
return result;
}
/**
* yyyy-MM-dd'T'HH:mm:ss.SSSZ转换yyyy-MM-dd HH:mm:ss
* 2022-11-07T20:50:15.144+08:00转换2022-11-07 20:51:51
* SSS表示毫秒
* Z表示时区
*/
private static void toUtcRfcString(){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date=null;
try {
date = simpleDateFormat.parse(formateUtcRfc(new Date()));
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(simpleDateFormat1.format(date));
}
/**
* yyyy-MM-dd'T'HH:mm:ss.SSSXXX转换yyyy-MM-dd HH:mm:ss
* 2022-11-07T20:51:51.704+0800转换2022-11-07 20:51:51
* SSS表示毫秒
* XXX表示时区时间格式
*/
private static void toUtcIsoString(){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date=null;
try {
date = simpleDateFormat.parse(formateUtcIso(new Date()));
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(simpleDateFormat1.format(date));
}
private static final Map<ISO, String> ISO_PATTERNS;
static {
Map<ISO, String> formats = new EnumMap<>(ISO.class);
formats.put(ISO.DATE, "yyyy-MM-dd");
formats.put(ISO.TIME, "HH:mm:ss.SSSXXX");
formats.put(ISO.DATE_TIME, "yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
ISO_PATTERNS = Collections.unmodifiableMap(formats);
}
public enum DateField {
/**
* 世纪
*
* @see Calendar#ERA
*/
ERA(Calendar.ERA),
/**
* 年
*
* @see Calendar#YEAR
*/
YEAR(Calendar.YEAR),
/**
* 月
*
* @see Calendar#MONTH
*/
MONTH(Calendar.MONTH),
/**
* 一年中第几周
*
* @see Calendar#WEEK_OF_YEAR
*/
WEEK_OF_YEAR(Calendar.WEEK_OF_YEAR),
/**
* 一月中第几周
*
* @see Calendar#WEEK_OF_MONTH
*/
WEEK_OF_MONTH(Calendar.WEEK_OF_MONTH),
/**
* 一月中的第几天
*
* @see Calendar#DAY_OF_MONTH
*/
DAY_OF_MONTH(Calendar.DAY_OF_MONTH),
/**
* 一年中的第几天
*
* @see Calendar#DAY_OF_YEAR
*/
DAY_OF_YEAR(Calendar.DAY_OF_YEAR),
/**
* 周几,1表示周日,2表示周一
*
* @see Calendar#DAY_OF_WEEK
*/
DAY_OF_WEEK(Calendar.DAY_OF_WEEK),
/**
* 天所在的周是这个月的第几周
*
* @see Calendar#DAY_OF_WEEK_IN_MONTH
*/
DAY_OF_WEEK_IN_MONTH(Calendar.DAY_OF_WEEK_IN_MONTH),
/**
* 上午或者下午
*
* @see Calendar#AM_PM
*/
AM_PM(Calendar.AM_PM),
/**
* 小时,用于12小时制
*
* @see Calendar#HOUR
*/
HOUR(Calendar.HOUR),
/**
* 小时,用于24小时制
*
* @see Calendar#HOUR
*/
HOUR_OF_DAY(Calendar.HOUR_OF_DAY),
/**
* 分钟
*
* @see Calendar#MINUTE
*/
MINUTE(Calendar.MINUTE),
/**
* 秒
*
* @see Calendar#SECOND
*/
SECOND(Calendar.SECOND),
/**
* 毫秒
*
* @see Calendar#MILLISECOND
*/
MILLISECOND(Calendar.MILLISECOND);
// ---------------------------------------------------------------
private final int value;
DateField(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
/**
* 将 {@link Calendar}相关值转换为DatePart枚举对象<br>
*
* @param calendarPartIntValue Calendar中关于Week的int值
* @return DateField
*/
public static DateField of(int calendarPartIntValue) {
switch (calendarPartIntValue) {
case Calendar.ERA:
return ERA;
case Calendar.YEAR:
return YEAR;
case Calendar.MONTH:
return MONTH;
case Calendar.WEEK_OF_YEAR:
return WEEK_OF_YEAR;
case Calendar.WEEK_OF_MONTH:
return WEEK_OF_MONTH;
case Calendar.DAY_OF_MONTH:
return DAY_OF_MONTH;
case Calendar.DAY_OF_YEAR:
return DAY_OF_YEAR;
case Calendar.DAY_OF_WEEK:
return DAY_OF_WEEK;
case Calendar.DAY_OF_WEEK_IN_MONTH:
return DAY_OF_WEEK_IN_MONTH;
case Calendar.AM_PM:
return AM_PM;
case Calendar.HOUR:
return HOUR;
case Calendar.HOUR_OF_DAY:
return HOUR_OF_DAY;
case Calendar.MINUTE:
return MINUTE;
case Calendar.SECOND:
return SECOND;
case Calendar.MILLISECOND:
return MILLISECOND;
default:
return null;
}
}
}
十八、FastJson中Json数组转换List<T>
class Function{
private String functionId;
private Boolean needBuy;
private String functionName;
public Function(){
}
public Function(String functionId, Boolean needBuy, String functionName) {
this.functionId = functionId;
this.needBuy = needBuy;
this.functionName = functionName;
}
public String getFunctionId() {
return functionId;
}
public void setFunctionId(String functionId) {
this.functionId = functionId;
}
public Boolean getNeedBuy() {
return needBuy;
}
public void setNeedBuy(Boolean needBuy) {
this.needBuy = needBuy;
}
public String getFunctionName() {
return functionName;
}
public void setFunctionName(String functionName) {
this.functionName = functionName;
}
@Override
public String toString() {
return "Function{" +
"functionId='" + functionId + '\'' +
", needBuy=" + needBuy +
", functionName='" + functionName + '\'' +
'}';
}
}
String jsonStr= "[{\"functionId\":\"14\",\"needBuy\":false,\"functionName\":\"功能1\"},{\"functionId\":\"17\",\"needBuy\":false,\"functionName\":\"功能2\"}]";
// JSONArray转换List<T>
List<Function> functions = JSON.parseArray(jsonStr, Function.class);
// JSONObject实现
List<Function> list = jsonArray.stream().map(item -> {
Function function = JSONObject.parseObject(JSONObject.toJSONString(item), Function.class);
return function;
}).collect(Collectors.toList());
Idea将字符串转化为JSON字符串的方式 :鼠标放在括号内,然后Alt+Enter即可看到编辑.
十九、时间月份增加或者减少
主要使用java8的LocalDate.now().plusMonths
/**
* 默认是增加月份
*
* @param num
* @return
*/
private static List<String> getRangDateMonthList(int num){
return getRangDateMonthList(num,true);
}
/**
* 返回指定月份的集合
* @param num 月份
* @param status 状态,true为增加,false为减少
* @return
*/
private static List<String> getRangDateMonthList(int num,boolean status){
if(num<=0){
return Collections.emptyList();
}
List<String> list=new ArrayList<>();
for(int i=0;i<num;i++){
long plus=i;
if(!status){
plus=Long.parseLong("-"+i);
}
list.add(LocalDate.now().plusMonths(plus).toString().substring(0,7));
}
return list;
}
二十、函数式接口的封装使用
1、定义函数式接口
package com.boot.skywalk.task;
/**
* 通用数据清理任务接口
*/
@FunctionalInterface
public interface ICleanData {
/**
* 清理数据
*/
void cleanData();
}
package com.boot.skywalk.task;
/**
* 通用检验
* @param <T>
*/
@FunctionalInterface
public interface ICheck<T> {
/**
* 通用检验
* @param t
*/
void check(T t);
}
Dubbo中的检验,可以扩展为函数式接口
package org.apache.dubbo.common.status;
import org.apache.dubbo.common.extension.ExtensionScope;
import org.apache.dubbo.common.extension.SPI;
/**
* StatusChecker
*/
@SPI(scope = ExtensionScope.APPLICATION)
public interface StatusChecker {
/**
* check status
*
* @return status
*/
Status check();
}
定时任务上传采集数据
import org.apache.dubbo.common.extension.SPI;
@SPI
public interface Merger<T> {
T merge(T... items);
}
package org.apache.dubbo.rpc.cluster.merger;
import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.rpc.cluster.Merger;
import java.util.Arrays;
import java.util.Objects;
public class IntArrayMerger implements Merger<int[]> {
@Override
public int[] merge(int[]... items) {
if (ArrayUtils.isEmpty(items)) {
return new int[0];
}
return Arrays.stream(items).filter(Objects::nonNull)
.flatMapToInt(Arrays::stream)
.toArray();
}
}
计算机存储空间
/**
* 计算Windows机器磁盘信息
*
* @param path
* @return
*/
public static String getFileSpace(String path){
if(StringUtils.isBlank(path)){
throw new IllegalArgumentException("path is null");
}
File file = new File(path+File.separator);
// 单位是B
long freeSpace = file.getFreeSpace();
long totalSpace = file.getTotalSpace();
long usableSpace = file.getUsableSpace();
long usedSpace = totalSpace-usableSpace;
StringJoiner stringJoiner = new StringJoiner(",","[","]");
stringJoiner.add("空闲空间:"+freeSpace/1024/1024/1024+"GB")
.add("总空间:"+totalSpace/1024/1024/1024+"GB")
.add("可用空间:"+usableSpace/1024/1024/1024+"GB")
.add("已用空间:"+usedSpace/1024/1024/1024+"GB");
return stringJoiner.toString();
}
二十一 自定义实现栈
package com.alibaba.dubbo.common.utils;
import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.List;
/**
* Stack.
*/
public class Stack<E> {
private int mSize = 0;
private List<E> mElements = new ArrayList<E>();
public Stack() {
}
/**
* push.
*
* @param ele
*/
public void push(E ele) {
if (mElements.size() > mSize)
mElements.set(mSize, ele);
else
mElements.add(ele);
mSize++;
}
/**
* pop.
*
* @return the last element.
*/
public E pop() {
if (mSize == 0)
throw new EmptyStackException();
return mElements.set(--mSize, null);
}
/**
* peek.
*
* @return the last element.
*/
public E peek() {
if (mSize == 0)
throw new EmptyStackException();
return mElements.get(mSize - 1);
}
/**
* get.
*
* @param index index.
* @return element.
*/
public E get(int index) {
if (index >= mSize)
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mSize);
return index < 0 ? mElements.get(index + mSize) : mElements.get(index);
}
/**
* set.
*
* @param index index.
* @param value element.
* @return old element.
*/
public E set(int index, E value) {
if (index >= mSize)
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mSize);
return mElements.set(index < 0 ? index + mSize : index, value);
}
/**
* remove.
*
* @param index
* @return element
*/
public E remove(int index) {
if (index >= mSize)
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mSize);
E ret = mElements.remove(index < 0 ? index + mSize : index);
mSize--;
return ret;
}
/**
* get stack size.
*
* @return size.
*/
public int size() {
return mSize;
}
/**
* is empty.
*
* @return empty or not.
*/
public boolean isEmpty() {
return mSize == 0;
}
/**
* clear stack.
*/
public void clear() {
mSize = 0;
mElements.clear();
}
}
二十二、多种Json框架解析适配,看dubbo的框架代码
1、定义JSON接口,【常用业务方法】
public interface JSON {
boolean isSupport();
<T> T toJavaObject(String json, Type type);
<T> List<T> toJavaList(String json, Class<T> clazz);
String toJson(Object obj);
List<?> getList(Map<String, ?> obj, String key);
List<Map<String, ?>> getListOfObjects(Map<String, ?> obj, String key);
List<String> getListOfStrings(Map<String, ?> obj, String key);
Map<String, ?> getObject(Map<String, ?> obj, String key);
Double getNumberAsDouble(Map<String, ?> obj, String key);
Integer getNumberAsInteger(Map<String, ?> obj, String key);
Long getNumberAsLong(Map<String, ?> obj, String key);
String getString(Map<String, ?> obj, String key);
List<Map<String, ?>> checkObjectList(List<?> rawList);
List<String> checkStringList(List<?> rawList);
}
2、AbstractJSONImpl【常用的类型转换校验】
package org.apache.dubbo.common.json.impl;
import org.apache.dubbo.common.json.JSON;
import java.util.List;
import java.util.Map;
public abstract class AbstractJSONImpl implements JSON {
@Override
public List<?> getList(Map<String, ?> obj, String key) {
assert obj != null;
assert key != null;
if (!obj.containsKey(key)) {
return null;
}
Object value = obj.get(key);
if (!(value instanceof List)) {
throw new ClassCastException(
String.format("value '%s' for key '%s' in '%s' is not List", value, key, obj));
}
return (List<?>) value;
}
/**
* Gets a list from an object for the given key, and verifies all entries are objects. If the key
* is not present, this returns null. If the value is not a List or an entry is not an object,
* throws an exception.
*/
@Override
public List<Map<String, ?>> getListOfObjects(Map<String, ?> obj, String key) {
assert obj != null;
List<?> list = getList(obj, key);
if (list == null) {
return null;
}
return checkObjectList(list);
}
/**
* Gets a list from an object for the given key, and verifies all entries are strings. If the key
* is not present, this returns null. If the value is not a List or an entry is not a string,
* throws an exception.
*/
@Override
public List<String> getListOfStrings(Map<String, ?> obj, String key) {
assert obj != null;
List<?> list = getList(obj, key);
if (list == null) {
return null;
}
return checkStringList(list);
}
/**
* Gets an object from an object for the given key. If the key is not present, this returns null.
* If the value is not a Map, throws an exception.
*/
@SuppressWarnings("unchecked")
@Override
public Map<String, ?> getObject(Map<String, ?> obj, String key) {
assert obj != null;
assert key != null;
if (!obj.containsKey(key)) {
return null;
}
Object value = obj.get(key);
if (!(value instanceof Map)) {
throw new ClassCastException(
String.format("value '%s' for key '%s' in '%s' is not object", value, key, obj));
}
return (Map<String, ?>) value;
}
/**
* Gets a number from an object for the given key. If the key is not present, this returns null.
* If the value does not represent a double, throws an exception.
*/
@Override
public Double getNumberAsDouble(Map<String, ?> obj, String key) {
assert obj != null;
assert key != null;
if (!obj.containsKey(key)) {
return null;
}
Object value = obj.get(key);
if (value instanceof Double) {
return (Double) value;
}
if (value instanceof String) {
try {
return Double.parseDouble((String) value);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
String.format("value '%s' for key '%s' is not a double", value, key));
}
}
throw new IllegalArgumentException(
String.format("value '%s' for key '%s' in '%s' is not a number", value, key, obj));
}
/**
* Gets a number from an object for the given key, casted to an integer. If the key is not
* present, this returns null. If the value does not represent an integer, throws an exception.
*/
@Override
public Integer getNumberAsInteger(Map<String, ?> obj, String key) {
assert obj != null;
assert key != null;
if (!obj.containsKey(key)) {
return null;
}
Object value = obj.get(key);
if (value instanceof Double) {
Double d = (Double) value;
int i = d.intValue();
if (i != d) {
throw new ClassCastException("Number expected to be integer: " + d);
}
return i;
}
if (value instanceof String) {
try {
return Integer.parseInt((String) value);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
String.format("value '%s' for key '%s' is not an integer", value, key));
}
}
throw new IllegalArgumentException(
String.format("value '%s' for key '%s' is not an integer", value, key));
}
/**
* Gets a number from an object for the given key, casted to an long. If the key is not
* present, this returns null. If the value does not represent a long integer, throws an
* exception.
*/
@Override
public Long getNumberAsLong(Map<String, ?> obj, String key) {
assert obj != null;
assert key != null;
if (!obj.containsKey(key)) {
return null;
}
Object value = obj.get(key);
if (value instanceof Double) {
Double d = (Double) value;
long l = d.longValue();
if (l != d) {
throw new ClassCastException("Number expected to be long: " + d);
}
return l;
}
if (value instanceof String) {
try {
return Long.parseLong((String) value);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
String.format("value '%s' for key '%s' is not a long integer", value, key));
}
}
throw new IllegalArgumentException(
String.format("value '%s' for key '%s' is not a long integer", value, key));
}
/**
* Gets a string from an object for the given key. If the key is not present, this returns null.
* If the value is not a String, throws an exception.
*/
@Override
public String getString(Map<String, ?> obj, String key) {
assert obj != null;
assert key != null;
if (!obj.containsKey(key)) {
return null;
}
Object value = obj.get(key);
if (!(value instanceof String)) {
throw new ClassCastException(
String.format("value '%s' for key '%s' in '%s' is not String", value, key, obj));
}
return (String) value;
}
/**
* Casts a list of unchecked JSON values to a list of checked objects in Java type.
* If the given list contains a value that is not a Map, throws an exception.
*/
@SuppressWarnings("unchecked")
@Override
public List<Map<String, ?>> checkObjectList(List<?> rawList) {
assert rawList != null;
for (int i = 0; i < rawList.size(); i++) {
if (!(rawList.get(i) instanceof Map)) {
throw new ClassCastException(
String.format("value %s for idx %d in %s is not object", rawList.get(i), i, rawList));
}
}
return (List<Map<String, ?>>) rawList;
}
/**
* Casts a list of unchecked JSON values to a list of String. If the given list
* contains a value that is not a String, throws an exception.
*/
@SuppressWarnings("unchecked")
@Override
public List<String> checkStringList(List<?> rawList) {
assert rawList != null;
for (int i = 0; i < rawList.size(); i++) {
if (!(rawList.get(i) instanceof String)) {
throw new ClassCastException(
String.format(
"value '%s' for idx %d in '%s' is not string", rawList.get(i), i, rawList));
}
}
return (List<String>) rawList;
}
}
3、GsonImpl【Gson框架实现】
package org.apache.dubbo.common.json.impl;
import org.apache.dubbo.common.utils.ClassUtils;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
public class GsonImpl extends AbstractJSONImpl {
// weak reference of com.google.gson.Gson, prevent throw exception when init
private volatile Object gsonCache = null;
@Override
public boolean isSupport() {
try {
Class<?> aClass = ClassUtils.forName("com.google.gson.Gson");
return aClass != null;
} catch (Throwable t) {
return false;
}
}
@Override
public <T> T toJavaObject(String json, Type type) {
return getGson().fromJson(json, type);
}
@Override
public <T> List<T> toJavaList(String json, Class<T> clazz) {
return getGson().fromJson(json, TypeToken.getParameterized(List.class, clazz).getType());
}
@Override
public String toJson(Object obj) {
return getGson().toJson(obj);
}
private Gson getGson() {
if (gsonCache == null || !(gsonCache instanceof Gson)) {
synchronized (this) {
if (gsonCache == null || !(gsonCache instanceof Gson)) {
gsonCache = new Gson();
}
}
}
return (Gson) gsonCache;
}
}
4、FastJsonImpl【FastJson框架】
package org.apache.dubbo.common.json.impl;
import org.apache.dubbo.common.utils.ClassUtils;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.lang.reflect.Type;
import java.util.List;
public class FastJsonImpl extends AbstractJSONImpl {
@Override
public boolean isSupport() {
try {
Class<?> aClass = ClassUtils.forName("com.alibaba.fastjson.JSON");
return aClass != null;
} catch (Throwable t) {
return false;
}
}
@Override
public <T> T toJavaObject(String json, Type type) {
return com.alibaba.fastjson.JSON.parseObject(json, type);
}
@Override
public <T> List<T> toJavaList(String json, Class<T> clazz) {
return com.alibaba.fastjson.JSON.parseArray(json, clazz);
}
@Override
public String toJson(Object obj) {
return com.alibaba.fastjson.JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);
}
}
5、JsonUtil框架工具类【根据配置项选择使用】
String PREFER_JSON_FRAMEWORK_NAME = "dubbo.json-framework.prefer";
package org.apache.dubbo.common.utils;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.json.JSON;
import org.apache.dubbo.common.json.impl.FastJsonImpl;
import org.apache.dubbo.common.json.impl.GsonImpl;
import java.util.Arrays;
import java.util.List;
public class JsonUtils {
private static volatile JSON json;
public static JSON getJson() {
if (json == null) {
synchronized (JsonUtils.class) {
if (json == null) {
String preferJsonFrameworkName = System.getProperty(CommonConstants.PREFER_JSON_FRAMEWORK_NAME);
if (StringUtils.isNotEmpty(preferJsonFrameworkName)) {
try {
JSON instance = null;
switch (preferJsonFrameworkName) {
case "fastjson":
instance = new FastJsonImpl();
break;
case "gson":
instance = new GsonImpl();
break;
}
if (instance != null && instance.isSupport()) {
json = instance;
}
} catch (Throwable ignore) {
}
}
if (json == null) {
List<Class<? extends JSON>> jsonClasses = Arrays.asList(
FastJsonImpl.class,
GsonImpl.class);
for (Class<? extends JSON> jsonClass : jsonClasses) {
try {
JSON instance = jsonClass.getConstructor().newInstance();
if (instance.isSupport()) {
json = instance;
break;
}
} catch (Throwable ignore) {
}
}
}
if (json == null) {
throw new IllegalStateException("Dubbo unable to find out any json framework (e.g. fastjson, gson) from jvm env. " +
"Please import at least one json framework.");
}
}
}
}
return json;
}
/**
* @deprecated for uts only
*/
@Deprecated
protected static void setJson(JSON json) {
JsonUtils.json = json;
}
}
二十三、优化if/else/switch的方法,降低程序圈复杂度、提高扩展性.
1、使用卫语句提前返回,包括各种配置项检查、断言检查、参数校验等.
2、使用三目表达式.
3、使用Optional来减少返回.
4、使用静态块+Map的缓存.
5、使用策略模式来减少不必要的分支.
6、使用枚举结合方法来实现.
7、开发完功能后,整理代码,包括格式化命名,圈复杂度和深度,以及IDAE重构快捷键抽取一下,提供复用,减少重复.
8、多阅读开源框架代码,学习实践设计模式、编码技巧、软件设计思想对日常开发很有帮助.