Java开发工具积累(符合阿里巴巴手册规范)
文章目录
- 一、命名规约
- 二、代码格式
- 三、集合篇
- 1. 栈、队列、双端队列
- 2. List的升序倒序
- 3. Map的升序降序
- 4. 二维数组排序
- 5. 集合之间的转换
- 6. Map键值对遍历
- 7. 重写equal与hashCode
- 8. ArrayList的subList
- 9. keySet()/values()/entrySet()
- 10. Collections.emptyList()
- 11. Collections.singletonList(str)
- 12. Collection接口的addAll()
- 13. foreach与iterator()
- 14. 使用Set去重
- 四、并发篇
- 1. 创建线程池
- 2. ThreadLocal的使用
- 五、时间篇
- 1. LocalDateTime的使用
- 2. String、Date、LocalDateTime转换
- 六、控制块
- 1. switch
- 2. 三目运算
- 3. 循环体
- 4. try-catch-finally-return
- 七、其他
- 1. 正则表达式
- 2. BeanUtil的copy
- 3. Integer的比较
- 4. 浮点数的比较
- 5. Object的clone方法
一、命名规约
A) 各类命名方法
类名:UserController、UserService、UserMapper
模型名:User、UserDTO、UserVO
对象名:userController
常量名:USER_NAMEB) Service/DAO 层方法命名规约
1) 获取单个对象的方法用 get 做前缀。
2) 获取多个对象的方法用 list 做前缀,复数结尾,如:listObjects。
3) 获取统计值的方法用 count 做前缀。
4) 插入的方法用 save/insert 做前缀。
5) 删除的方法用 remove/delete 做前缀。
6) 修改的方法用 update 做前缀。注意:POJO 类中布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列化错误。
二、代码格式
1. if/for/while/switch/do 等保留字与括号之间都必须加空格
2. 任何二目、三目运算符的左右两边都需要加一个空格,包括赋值运算符=、逻辑运算符&&、加减乘除符号等。
3. 注释的双斜线与注释内容之间有且仅有一个空格。
4. 在进行类型强制转换时,右括号与强制转换值之间不需要任何空格隔开。
5. 方法参数在定义和传入时,多个参数逗号后边必须加空格。
三、集合篇
1. 栈、队列、双端队列
Stack<Integer> stack = new Stack<>(); // 栈stack.push(1); // 压入stack.pop(); // 弹出stack.peek(); // 获取但不弹出Queue<Integer> queue = new ArrayDeque<>(); //队列queue.offer(1); //压入queue.poll(); // 弹出queue.peek(); // 获取但不弹出Deque<Integer> deque = new ArrayDeque<>(); // 双端队列deque.offerFirst(1); // 压入队头deque.offerLast(2); // 压入对尾deque.pollFirst(); // 弹出队头deque.pollLast(); // 弹出队尾deque.peekFirst(); // 获取队头但不弹出deque.peekLast(); // 获取队尾但不弹出
2. List的升序倒序
List<Integer> list = Arrays.asList(10,1,6,4,8,7,9,3,2,5);System.out.println("原始数据:");list.forEach(n ->{System.out.print(n+", ");});System.out.println("");System.out.println("升序排列:");Collections.sort(list); // 升序排列list.forEach(n ->{System.out.print(n+", ");});// 降序的话:需要先升序再倒序,才能有降序的结果System.out.println("");System.out.println("降序排列:");Collections.reverse(list); // 倒序排列list.forEach(n ->{System.out.print(n+", ");});
3. Map的升序降序
Map<Integer, String> map = new HashMap<>();map.put(100, "I'am a");map.put(99, "I'am c");map.put(2, "I'am d");map.put(33, "I'am b");// 按照value进行倒排,如果要根据key进行排序的话使用Map.Entry.comparingByKey()map.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).forEach(System.out::println);// 根据value进行正序排序,根据key进行排序的话使用comparingByKey()map.entrySet().stream().sorted(Map.Entry.comparingByValue()).forEach(System.out::println);// 如果要将排序的结果返回的话,我们可以使用下面的方法(注意:要使用LinkedHashMap进行保存,linkedHashMap可以保存插入顺序)Map<Integer, String> resultMap1 = map.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (s, s2) -> s,LinkedHashMap::new));// 下面的这种写法同上面的写法,只不过是将简写展开了,这样更易于理解Map<Integer, String> resultMap = map.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(Collectors.toMap(new Function<Map.Entry<Integer, String>, Integer>() {@Overridepublic Integer apply(Map.Entry<Integer, String> integerStringEntry) {return integerStringEntry.getKey();}}, new Function<Map.Entry<Integer, String>, String>() {@Overridepublic String apply(Map.Entry<Integer, String> integerStringEntry) {return integerStringEntry.getValue();}}, new BinaryOperator<String>() {@Overridepublic String apply(String s, String s2) {return s;}}, new Supplier<Map<Integer, String>>() {@Overridepublic Map<Integer, String> get() {return new LinkedHashMap<>();}}));// 同样如果需要将排序的将结果作为Map进行返回我们还可以使用下面的方法,但是不推荐这种方式(effectivejava 178页中说:foreach操作应该只用于报告stream计算的结果,而不是执行计算)Map<Integer, String> result2 = new LinkedHashMap<>();map.entrySet().stream().sorted(Map.Entry.comparingByValue()).forEach(new Consumer<Map.Entry<Integer, String>>() {@Overridepublic void accept(Map.Entry<Integer, String> integerStringEntry) {result2.put(integerStringEntry.getKey(), integerStringEntry.getValue());}});
4. 二维数组排序
Arrays.sort(intervals, new Comparator<int[]>() {public int compare(int[] interval1, int[] interval2) {return interval1[0] - interval2[0];}});
5. 集合之间的转换
// Object转基本元素
List<String> tableNames=list.stream().map(User::getMessage).collect(Collectors.toList());// Object转Map
Map<String, Account> map = accounts.stream().collect(Collectors.toMap(Account::getUsername, Function.identity(), (key1, key2) -> key2));// Object转Map
/** * 1. 避免key重复* 在使用 java.util.stream.Collectors 类的 toMap()方法转为 Map 集合时,一定要使* 用含有参数类型为 BinaryOperator,参数名为 mergeFunction 的方法,否则当出现相同 key* 值时会抛出 IllegalStateException 异常。* 说明:参数 mergeFunction 的作用是当出现 key 重复时,自定义对 value 的处理策略* 2. 避免值为null* 在使用 java.util.stream.Collectors 类的 toMap()方法转为 Map 集合时,一定要注* 意当 value 为 null 时会抛 NPE 异常。
**/
Map<Long, String> getIdNameMap = accounts.stream().collect(Collectors.toMap(Account::getId, Account::getUsernamee, (v1, v2) -> v2));// String转Long
List<Long>=stringList.stream().map(Long::valueOf).collect(Collectors.toList());// Long转String
List<String>=longList.stream().map(String::valueOf).collect(Collectors.toList());// Integer转Long
List<Long> listLong = JSONArray.parseArray(listInt.toString(),Long.class);// Long 转Integer
List<Integer> integerList = JSONArray.parseArray(LongList.toString(), Integer.class);
// 或者
List<Integer> integerList = longList.stream().map(x -> Integer.valueOf(String.valueOf(x))).collect(Collectors.toList());// JSONArray转List
JSONArray jsonArray = updateApplicationSchemaDTO.getJSONArray("configTrophyDTOList");
configTrophyDTOList = jsonArray.toJavaList(ConfigTrophyDTO.class);// List转数组
// 使用集合转数组的方法,必须使用集合的 toArray(T[] array)
String[] array = list.toArray(new String[0]);// 数组转List
/**
1. 使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,
它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。
2. asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。Arrays.asList 体现的是适配器模式,只是转换接口,后台的数据仍是数组。
**/
List list = Arrays.asList(strArray);
6. Map键值对遍历
不推荐使用ketSet()获取键集合,再遍历value,这样的性能较低。keySet 其实是遍历了 2 次,一次是转为 Iterator 对象,另一次是从 hashMap 中取出 key 所对应的value。而 entrySet 只是遍历了一次就把 key 和 value 都放到了 entry 中,效率更高。如果是 JDK8,使用
Map.forEach 方法。
System.out.println("====4、通过entrySet()获得key-value值——使用迭代器遍历====");
Set set1 = hashMap.entrySet();
Iterator iterator1 = set1.iterator();
while(iterator1.hasNext()){Object itset = iterator1.next();Map.Entry entry = (Map.Entry) itset;System.out.println(entry.getKey()+"-"+entry.getValue());
}
7. 重写equal与hashCode
package jianlejun.study;public class Student {private String name;// 姓名private String sex;// 性别private String age;// 年龄private float weight;// 体重private String addr;// 地址// 重写hashcode方法@Overridepublic int hashCode() {int result = name.hashCode();result = 17 * result + sex.hashCode();result = 17 * result + age.hashCode();return result;}// 重写equals方法@Overridepublic boolean equals(Object obj) {if(!(obj instanceof Student)) {// instanceof 已经处理了obj = null的情况return false;}Student stuObj = (Student) obj;// 地址相等if (this == stuObj) {return true;}// 如果两个对象姓名、年龄、性别相等,我们认为两个对象相等if (stuObj.name.equals(this.name) && stuObj.sex.equals(this.sex) && stuObj.age.equals(this.age)) {return true;} else {return false;}}
}
8. ArrayList的subList
- ArrayList 的 subList 结果不可强转成 ArrayList,否则会抛出 ClassCastException 异
常:java.util.RandomAccessSubList cannot be cast to java.util.ArrayList。因为subList 返回的是 ArrayList 的内部类 SubList。此外subList()返回原来list的从[fromIndex, toIndex)之间这一部分的视图,之所以说是视图,是因为实际上,返回的list是靠原来的list支持的。 - 在 subList 场景中,高度注意对父集合元素的增加或删除,均会导致子列表的遍历、
增加、删除产生 ConcurrentModificationException 异常。
// 左闭右开
List<String> list = arrayList.subList(1,3);// 如果想防止原list被改变可以这样操作
List<Integer> sub = new ArrayList<Integer>(test.subList(1, 3));
9. keySet()/values()/entrySet()
使用 Map 的方法 keySet()/values()/entrySet()返回集合对象时,不可以对其进行添
加元素操作,否则会抛出 UnsupportedOperationException 异常。
10. Collections.emptyList()
- Collections.emptyList()返回一个空的List(list != null,size == 0),这是因为new ArrayList()创建时有初始大小,占用内存,emptyList()不用创建一个新的对象,可以减少内存开销;但是所以返回的List不能进行
增加
和删除
元素操作。
private static List<String> getList(String str) {if (StringUtils.isBlank(str)) {// 使用时不会报空指针return Collections.emptyList(); }List<String> list = new ArrayList<String>();list.add(str);return list;}
11. Collections.singletonList(str)
- 在实际的开发中,如果有特殊要求只需要List存放一个的元素,就可以使用Collections.singletonList作为数据结构来存放数据啦。
List<String> myList = Collections.singletonList(str);
12. Collection接口的addAll()
- 在使用 Collection 接口任何实现类的 addAll()方法时,都要对输入的集合参数进行
NPE 判断。
//1. addAll()测试//1.1 初始化多种情形的集合List<String> addList = null;List<String> addList1 = new ArrayList<String>();List<String> addList2 = new ArrayList<String>(Arrays.asList("epsilon", "zeta", "eta"));List<String> addList3 = new ArrayList<String>(Arrays.asList(null, "epsilon", "zeta", "eta"));//1.2 测试list.addAll(addList);//addList为null,报空指针list.addAll(addList1);//addList1为[],不报错list.addAll(addList2);//addList2无null,不报错list.addAll(addList3);//addList3有null,不报错
13. foreach与iterator()
不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator
方式
// 正例:
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {String item = iterator.next();if (删除元素的条件) {iterator.remove();}
}
// 反例:
for (String item : list) {if ("1".equals(item)) {list.remove(item);}
}
14. 使用Set去重
利用 Set 元素唯一的特性,可以快速对一个集合进行去重操作,避免使用 List 的
contains()进行遍历去重或者判断包含操作。
// Set集合去重,保持原来顺序public static void ridRepeat2(List<String> list) {System.out.println("list = [" + list + "]");List<String> listNew = new ArrayList<String>();Set set = new HashSet();for (String str : list) {if (set.add(str)) {listNew.add(str);}}System.out.println("listNew = [" + listNew + "]");}// Set去重 由于Set(HashSet)的无序性,不会保持原来顺序public static void ridRepeat3(List<String> list) {System.out.println("list = [" + list + "]");Set set = new HashSet();List<String> listNew = new ArrayList<String>();set.addAll(list);listNew.addAll(set);System.out.println("listNew = [" + listNew + "]");}// Set通过HashSet去重(将ridRepeat3方法缩减为一行) 无序public static void ridRepeat4(List<String> list) {System.out.println("list = [" + list + "]");List<String> listNew = new ArrayList<String>(new HashSet(list));System.out.println("listNew = [" + listNew + "]");}// Set通过TreeSet去重 会按字典顺序重排序public static void ridRepeat5(List<String> list) {System.out.println("list = [" + list + "]");List<String> listNew = new ArrayList<String>(new TreeSet<String>(list));System.out.println("listNew = [" + listNew + "]");}// Set通过LinkedHashSet去重 保持原来顺序public static void ridRepeat6(List<String> list) {System.out.println("list = [" + list + "]");List<String> listNew = new ArrayList<String>(new LinkedHashSet<String>(list));System.out.println("listNew = [" + listNew + "]");}
四、并发篇
1. 创建线程池
ThreadPoolExecutor 参数介绍
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {}
参数 1:corePoolSize
核心线程数,线程池中始终存活的线程数。
参数 2:maximumPoolSize
最大线程数,线程池中允许的最大线程数,当线程池的任务队列满了之后可以创建的最大线程数。
参数 3:keepAliveTime
最大线程数可以存活的时间,当线程中没有任务执行时,最大线程就会销毁一部分,最终保持核心线程数量的线程。
参数 4:unit:
单位是和参数 3 存活时间配合使用的,合在一起用于设定线程的存活时间 ,参数 keepAliveTime 的时间单位有以下 7 种可选:
TimeUnit.DAYS:天
TimeUnit.HOURS:小时
TimeUnit.MINUTES:分
TimeUnit.SECONDS:秒
TimeUnit.MILLISECONDS:毫秒
TimeUnit.MICROSECONDS:微妙
TimeUnit.NANOSECONDS:纳秒
参数 5:workQueue
一个阻塞队列,用来存储线程池等待执行的任务,均为线程安全,它包含以下 7 种类型:较常用的是 LinkedBlockingQueue 和 Synchronous,线程池的排队策略与 BlockingQueue 有关。
ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列,即直接提交给线程不保持它们。
PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。与SynchronousQueue类似,还含有非阻塞方法。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
参数 6:threadFactory
线程工厂,主要用来创建线程,默认为正常优先级、非守护线程。
参数 7:handler
拒绝策略,拒绝处理任务时的策略,系统提供了 4 种可选:默认策略为 AbortPolicy。
AbortPolicy:拒绝并抛出异常。
CallerRunsPolicy:使用当前调用的线程来执行此任务。
DiscardOldestPolicy:抛弃队列头部(最旧)的一个任务,并执行当前任务。
DiscardPolicy:忽略并抛弃当前任务。
ThreadPoolExecutor执行流程
ThreadPoolExecutor 关键节点的执行流程如下:
- 当线程数小于核心线程数时,创建线程。
- 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
- 当线程数大于等于核心线程数,且任务队列已满:若线程数小于最大线程数,创建线程;若线程数等于最大线程数,抛出异常,拒绝任务。
ThreadPoolExecutor自定义拒绝策略
public static void main(String[] args) {// 任务的具体方法Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println("当前任务被执行,执行时间:" + new Date() +" 执行线程:" + Thread.currentThread().getName());try {// 等待 1sTimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}};// 创建线程,线程的任务队列的长度为 1ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, 1,100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1),new RejectedExecutionHandler() {@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {// 执行自定义拒绝策略的相关操作System.out.println("我是自定义拒绝策略~");}});// 添加并执行 4 个任务threadPool.execute(runnable);threadPool.execute(runnable);threadPool.execute(runnable);threadPool.execute(runnable);
}
2. ThreadLocal的使用
/**
ThreadLocal的api很简单,就4个* get——获取threadlocal局部变量* set——设置threadlocal局部变量* initialvalue——设置局部变量的初始值* remove——删除该局部变量
**/
public class SequenceNumber { // ThreadLocal 对象使用 static 修饰,ThreadLocal 无法解决共享对象的更新问题。private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){ public Integer initialValue(){ return 0; } }; public int getNextNum() { seqNum.set(seqNum.get() + 1); return seqNum.get(); } public static void main(String[] args) { SequenceNumber sn = new SequenceNumber(); TestClient t1 = new TestClient(sn); TestClient t2 = new TestClient(sn); TestClient t3 = new TestClient(sn); t1.start(); t2.start(); t3.start(); t1.print(); t2.print(); t3.print(); }
}private static class TestClient extends Thread { private SequenceNumber sn; public TestClient(SequenceNumber sn ) { this.sn = sn; } public void run() { for(int i=0; i< 3; i++) { System.out.println( Thread.currentThread().getName() + " --> " + sn.getNextNum()); } } public void print() { for(int i=0; i< 3; i++) { System.out.println( Thread.currentThread().getName() + " --> " + sn.getNextNum()); } }
}
Thread-2 --> 1
Thread-2 --> 2
Thread-2 --> 3
Thread-0 --> 1
Thread-0 --> 2
Thread-0 --> 3
Thread-1 --> 1
Thread-1 --> 2
Thread-1 --> 3
main --> 1
main --> 2
main --> 3
main --> 4
main --> 5
main --> 6
main --> 7
main --> 8
main --> 9
结论:可以发现,static的ThreadLocal变量是一个与线程相关的静态变量,即一个线程内,static变量是被各个实例共同引用的,但是不同线程内,static变量是隔开的。
五、时间篇
1. LocalDateTime的使用
// 获取当前时间
LocalDateTime now = LocalDateTime.now();// 获取指定时间
LocalDateTime localDateTime = LocalDateTime.of(2021, 6, 16, 16, 37, 20, 814 * 1000 * 1000);
LocalDateTime ldt = LocalDateTime.now().withYear(2021).withMonth(6).withDayOfMonth(16).withHour(10).withMinute(10).withSecond(59).withNano(999 * 1000 * 1000);// 获取指定时区时间
LocalDateTime datetime = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
LocalDateTime datetime2 = LocalDateTime.now(ZoneId.of("+8"));// 获取年月日信息
LocalDateTime now = LocalDateTime.now();
int year = now.getYear();
int month = now.getMonthValue();
int dayOfYear = now.getDayOfYear();
int dayOfMonth = now.getDayOfMonth();
int hour = now.getHour();
int minute = now.getMinute();
int second = now.getSecond();
int nano = now.getNano();// 日期计算
LocalDateTime now = LocalDateTime.now();
LocalDateTime tomorrow = now.plusDays(1L);
tomorrow = tomorrow.plusHours(2L);
tomorrow = tomorrow.plusMinutes(10L);LocalDateTime yesterday = now.minus(Duration.ofDays(1));
yesterday = yesterday.plusHours(2L);
yesterday = yesterday.plusMinutes(10L);// 时间格式化,DateTimeFormatter是线程安全的类。
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format = LocalDateTime.now().format(df);
2. String、Date、LocalDateTime转换
// LocalDateTime转Date
public static Date localDateTime2Date(LocalDateTime localDateTime) {return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
}// LocalDateTime转String
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static String localDateTime2String(LocalDateTime localDateTime) {return localDateTime.format(DATE_TIME_FORMATTER);
}// String 转 LocalDateTime,DateTimeFormatter是线程安全的类,可以将此类放到常量中。
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static LocalDateTime string2LocalDateTime(String str) {return LocalDateTime.parse(str, DATE_TIME_FORMATTER);
}// String 转 Date,SimpleDateFormat是非线程安全的类,在多线程操作时会报错。
public static Date string2Date(String str) throws ParseException {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return simpleDateFormat.parse(str);
}// Date 转 LocalDateTime
public static LocalDateTime date2LocalDateTime(Date date) {return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
}// Date 转 String
public static String date2String(Date date) {SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return formatter.format(date);
}
六、控制块
1. switch
public class SwitchString {public static void main(String[] args) {method("sth");}public static void method(String param) {// 1. 当 switch 括号内的变量类型为 String 并且为外部参数时,必须先进行 null判断。if(StringUtils.isEmpty(param)){return;}switch(param){case"sth": System.out.printin("it's sth"); break;case"sb": System.out.println("it's sb"); break;// 2. 在一个 switch 块内,都必须包含一个 default语句并且放在最后default: System.out.println("default"); break;}}
}
2. 三目运算
三目运算符 condition? 表达式 1 : 表达式 2 中,高度注意表达式 1 和 2 在类型对齐 时,可能抛出因自动拆箱导致的 NPE 异常。
// 反例
Integer a = 1;
Integer b = 2;
Integer c = null;
Boolean flag = false;
// a*b 的结果是 int 类型,那么 c 会强制拆箱成 int 类型,抛出 NPE 异常
Integer result=(flag? a*b : c);
3. 循环体
1. 循环体中的语句要考量性能,以下操作尽量移至循环体外处理,如定义对象、变量、 获取数据库连接,进行不必要的 try-catch 操作(这个 try-catch 是否可以移至循环体外)
4. try-catch-finally-return
- return的执行优先级高于finally的执行优先级,但是return语句执行完毕之后并不会马上结束函数,而是将结果保存到栈帧中的局部变量表中,然后继续执行finally块中的语句;
- 如果finally块中包含return语句,则不会对try块中要返回的值进行保护,而是直接跳到finally语句中执行,并最后在finally语句中返回,返回值是在finally块中改变之后的值
// return 1
public static int test1() {int x = 1;try {return x;} finally {x = 2;}
}// return 2
public static int test2() {int x = 1;try {return x;} finally {x = 2;return x;}
}
七、其他
1. 正则表达式
在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度。
// 反例
public void addSyncConfigToCache(String configName, ESSyncConfig config) {Pattern pattern = Pattern.compile(".*:(.*)://.*/(.*)\\?.*$");Matcher matcher = pattern.matcher(dataSource.getUrl());
}// 正例
private static final Pattern pattern = Pattern.compile(regexRule);
public void addSyncConfigToCache(String configName, ESSyncConfig config) {Matcher matcher = pattern.matcher(dataSource.getUrl());
}
2. BeanUtil的copy
Apache BeanUtils 性能较差,可以使用其他方案比如 Spring BeanUtils, Cglib BeanCopier,注意
均是浅拷贝。
Person source = Person("Alice", 25);
Person destination = new Person();
BeanUtils.copyProperties(destination, source);
3. Integer的比较
所有整型包装类对象之间值的比较,全部使用 equals 方法比较
Integer a = 123;
Integer b = 321;
a.equal(b); // false
4. 浮点数的比较
基本数据类型使用Math.abs(),包装类使用BigDecimal;
// 基本数据类型
float a = 1.0f - 0.9f;
float b = 0.9f - 0.8f;
float diff = 1e-6f;
if (Math.abs(a - b) < diff) {System.out.println("true");
}// 包装类
//禁止使用构造方法 BigDecimal(double)的方式把 double 值转化为 BigDecimal 对象。
BigDecimal a = new BigDecimal("1.0".toString());
BigDecimal b = BigDecimal.value(0.9f);
BigDecimal c = new BigDecimal("0.8".toString());
if (a.equals(b)) {System.out.println("false");
}
5. Object的clone方法
对象 clone 方法默认是浅拷贝,若想实现深拷贝需覆写 clone 方法实现域对象的深度遍历式拷贝。
public class Person implements Cloneable {private String name;private Integer age;private String sex;public Person() {super();}public Person(String name, Integer age, String sex) {super();this.name = name;this.age = age;this.sex = sex;}public void setName(String name) {this.name = name;}public void setAge(Integer age) {this.age = age;}public void setSex(String sex) {this.sex = sex;}@Overridepublic String toString() {return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";}public Person clone() throws CloneNotSupportedException {return (Person) super.clone();}public static void main(String[] args) {Person person = new Person("Jachen", 23, "boy");System.out.println("person:" + person);try {Person person2 = person.clone();System.out.println("person2:" + person2);System.out.println("person.equals(person2):"+ person2.equals(person));person2.setName("Anna");person2.setSex("girl");person2.setAge(22);System.out.println(person2.getClass() == person.getClass());} catch (CloneNotSupportedException e) {e.printStackTrace();}}
}
相关文章:

Java开发工具积累(符合阿里巴巴手册规范)
文章目录 一、命名规约二、代码格式三、集合篇1. 栈、队列、双端队列2. List的升序倒序3. Map的升序降序4. 二维数组排序5. 集合之间的转换6. Map键值对遍历7. 重写equal与hashCode8. ArrayList的subList9. keySet()/values()/ent…...

SiLM5350MDBCA-DG车规级隔离驱动芯片,我们能为汽车智能提供什么?
SiLM5350MDBCA-DG是一款适用于IGBT、MOSFET的单通道 隔离门极驱动器,具有10A拉电流和10A灌电流驱动能 力。提供内部钳位功能,可单独控制 上升时间和下降时间。 在 SOP8 封 装 中 具 有 3000VRMS 隔 离 耐 压 ( 符 合 UL1577)。 与…...
【开题报告】基于SpringBoot的企业财务管理系统的设计与实现
1.研究背景 随着全球经济的发展和市场竞争的加剧,企业财务管理变得越来越重要。企业需要一个高效、精确、安全的财务管理系统来管理企业的财务事务,提供准确的财务数据支持决策制定。传统的手工财务管理方式已经无法满足企业的需求,因此&…...

【C盘清理】Jetbrains全家桶(PyCharm、Clion……)更改 IDE 特定文件(配置、缓存、插件、日志等)存储位置
文章目录 一、官网说明二、更改 IDE 目录的位置1. 转到“帮助”|“编辑自定义属性”2. 各文件位置3. 以PyCharm系统目录为例4. 修改idea.properties 三、清理旧的 IDE 目录 一、官网说明 IDE 使用的目录官网说明 二、更改 IDE 目录的位置 默认情况下,PyCharm 将每…...
nginx部署vue项目
nginx部署vue 解决nginx中vue项目刷新报404问题解决nginx转发后端服务隐藏部分url访问url路径/prod-api/api经过nginx反向代理后,到达后端服务的实际url地址为/api。 解决nginx中vue项目刷新报404问题 location / { …...

Relocations for this machine are not implemented,IDA版本过低导致生成汇编代码失败
目录 1、问题描述 2、安卓app发生崩溃,需要查看汇编代码上下文去辅助分析 3、使用IDA打开.so动态库文件,提示Relocations for this machine are not implemented 4、IDA版本较老,不支持ARM64的指令集,使用7.0版本就可以了 5、…...

[ CTF ]【天格】战队WriteUp-第七届“强网杯”全国安全挑战赛
第七届“强网杯”全国安全挑战赛 2023.12.16~2023.12.17 文章目录 【Misc】Pyjail ! Its myFILTER !!!easyfuzz谍影重重2.0签到Pyjail ! Its myRevenge !!!server_8F6C72124774022B.py 问卷调查 【Reverse】ezre 【Web】happygame 【强网先锋】石头剪刀布TrieSpeedUpezreez_fmt…...

Android13音频录制适配
Android13音频录制适配 前言: 之前写过一篇音频录制的文章,当时是在Android10以下的手机可以成功录制和播放,但是Android10及以上手机提示创建文件失败,最近做过Android13的适配,索性一起把之前的录音也适配了&#…...

【Python】—— 如果使用matplotlib做数据可视化
matplotlib做数据可视化 相关知识掌握matplotlib的基本使用方法1. 折线图2. 散点图3. 柱状图4. 饼图5. 直方图6. 等高线图7. 图形定制 掌握数据处理的基本方法1. 数据筛选2. 缺失值处理3. 异常值处理 理解数据可视化的原则和方法1. 选择合适的图表类型2. 避免数据混淆3. 突出重…...
【MyBatis-Plus】多数据源分页配置(低版本暂时就支持一种(可选),高版本多支持)
【转载】一、Mybatis Plus 3.4 版本之后分页插件的变化 1、地址 Mybatis Plus 3.4版本之后分页插件的变化 2、内容 1、MybatisPlusInterceptor 从 Mybatis Plus 3.4.0 版本开始,不再使用旧版本的 PaginationInterceptor,而是使用 MybatisPlusInterce…...

Linux 特殊符号
目录 1. # 注释 2. ;命令分隔符 3. .. 上级目录 4. . 当前目录 5. " " 换行,解析变量 6. 换行,不解析变量 7. \ 和 / 8. !历史命令调用,取反 9. * 通配符 10. $ 调用变量 11. | 管道 12. || …...
TDengine 签约中船九院,助力航运业智能化转型升级
在大数据时代背景下,船舶智能化已经成为船舶制造与航运领域发展的必然趋势。智能船舶作为《中国制造 2025》中明确重点发展的领域,代表了船舶未来的方向,对于航运业的转型升级至关重要。其中,大数据的处理和运用成为船舶智能化转型…...

upload-labs笔记
简介 upload-labs是一个使用php语言编写的,专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共21关,每一关都包含着不同上传方式。 文件上传漏洞是指: Web 服务器允许用户将文件上传至其…...

Android Studio好用的插件推荐
目录 一、插件推荐 二、如何下载 1.点击File—>Settings 2.点击Plugins然后进行搜索下载 三、Android Studio 模板 一、插件推荐 这个插件可以为您自动生成Parcelable代码。Parcelable是一种用于在Android组件之间传递自定义对象的机制,但手动编写Parcela…...
第三十九章 其他特殊主题 - 映射 IRIS ID 以供导出
文章目录 第三十九章 其他特殊主题 - 映射 IRIS ID 以供导出控制导出时的命名空间前缀XMLPREFIX 第三十九章 其他特殊主题 - 映射 IRIS ID 以供导出 当在顶层映射 IRIS 对象(而不是作为另一个对象的属性)时,其内部 ID、OID 和全局唯一 ID 不…...

文件操作(下)
标题的顺序是接着之前写的,希望这篇博客对你有帮助 七. 随机读写函数 实际上,无论是读还是写,在一次调用顺序读写函数,文件指针会移到已经读过或者写过的下一个位置,从那个位置开始下一次读和写(在文件没有…...
面试必问-vue3中ref与这个reactive的区别
ref和reactive是Vue 3中两种不同的响应式数据处理方式。 ref:ref函数可以将普通的Javascript值转换为一个响应式引用。它返回一个包含.value属性的对象,可以通过读取或修改.value来操作引用的值。当引用的值发生变化时,Vue会自动追踪依赖并更…...

网络(九)三层路由、DHCP以及VRRP协议介绍
目录 一、三层路由 1. 定义 2. 交换原理 3. 操作演示 3.1 图示 3.2 LSW1新建vlan10、20、30,分别对应123接口均为access类型,接口4为trunkl类型,允许所有vlan通过 3.3 LSW2新建vlan10、20、30,配置接口1为trunk类型&…...

深度学习 Day19——P8YOLOv5-C3模块实现
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 | 接辅导、项目定制 文章目录 前言1 我的环境2 代码实现与执行结果2.1 前期准备2.1.1 引入库2.1.2 设置GPU(如果设备上支持GPU就使用GPU,否则使用C…...

轻量封装WebGPU渲染系统示例<51>- 视差贴图(Parallax Map)(源码)
视差纹理是一种片段着色阶段增强材质表面凹凸细节的技术。 这里在WebGPU的实时渲染材质管线中实现了视差贴图计算,以便增强相关的纹理细节表现力。 当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/material/src/voxgpu/sample/Para…...

51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...