🔖 Programming Cheat Sheet
2025-01-22 08:19:30    2.8k 字   
This post is also available in English and alternative languages.

1. 文档

  • 写接口文档,把对接人当 SB 看待,一定要写的很详细,防止后续扯皮、甩锅。
  • 文档后续变更,要同步 添加/更新 文档中的 变更记录,方便日后溯源。同时也方便自己迅速回忆。

2. 沟通

2.1. 客户沟通

在与客户沟通预期时几个原则:

  1. 一定要给客户选择权,永远不要说不,要有条件地说是。
  2. 降低期望的同时给予其他的补偿。
  3. 提高期望的同时附加更多的条件。
  4. 对于比较大的期望要分步骤达到客户的期望。
  5. 不要帮客户做决定,而是给客户提供尽可能多的选项,然后引导客户做决定。
客户沟通

3. IntelliJ IDEA

3.1. Java: 找不到符号

关键词:IntelliJ IDEA、lombok、maven

现象:build编译项目时,总是出现java:找不到符号这个错误提示,导致编译中断。

解决方案:settings -> Build,Exection,Deployment -> Compiler -> Shared build process VM options 输入框。

添加如下配置:-Djps.track.ap.dependencies=false


4. WebStorm

4.1. debug模式

项目正常启动后,按住 command + shift,然后点击local#url,自动开启debug模式。

注意:只对localhost地址有效,对Network地址无效。


4.2. Live Template

4.2.1. function

1
2
3
function $NAME$(): $TYPE$ {
$end$
}

4.2.2. 箭头函数

webStorm箭头函数
1
2
3
() => {
$end$
}

5. Java

5.1. API

API设计

5.2. @GetMapping 指定多个URL路径

在网上看资料时,看到 @GetMapping 注解的另一种用法,即:指定多个URL路径,这个之前并没有注意到过。

1
2
3
4
5
6
7
8
9
@GetMapping(value = {"/", "/{userId}"})
public Result getInfo(@PathVariable(value = "userId", required = false) String userId) {
if (StringUtils.isBlank(userId)) {
// 查询全部用户信息
return result;
}
// 查询单个用户信息信息
return result;
}

5.3. Spring 项目 PR

5.3.1. 提高Map遍历性能

1
2
3
4
5
6
7
8
9
10
// --before update
for (String attributeName : attributes.keySet()) {
Object value = attributes.get(attributeName);
}

// --after update
for (Map.Entry<String, Object> attributeEntry : attributes.entrySet()) {
String attributeName = attributeEntry.getKey();
Object value = attributeEntry.getValue();
}

5.3.2. StringJoiner

Java 8 中的 StringJoiner,可以设置连接符,还可以设置前置符和后置符。


5.3.3. ArrayList 初始化

1
2
3
4
5
6
// --before update
List<String> result = new ArrayList<>();
result.addAll(Arrays.asList(array1));

// --after update
List<String> result = new ArrayList<>(Arrays.asList(array1));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// --before update
List<String> matchingHeaderNames = new ArrayList<>();
if (headers != null) {
for (String key : headers.keySet()) {
if (PatternMatchUtils.simpleMatch(pattern, key)) {
matchingHeaderNames.add(key);
}
}
}

// --after update
if (headers == null) {
return Collections.emptyList();
}
List<String> matchingHeaderNames = new ArrayList<>();
for (String key : headers.keySet()) {
if (PatternMatchUtils.simpleMatch(pattern, key)) {
matchingHeaderNames.add(key);
}
}

new ArrayList<>(Arrays.asList(array1))Collections.emptyList() 都是一些值得关注的代码小技巧。

在第二个修改片段中,提前进行空值判断,提前中断,可以减少下面代码的括号嵌套层数。


5.3.4. 数组填充

1
2
3
4
5
6
7
// --before update
for (int i = 0; i < bytes.length; i++) {
bytes[i] = 'h';
}

// --after update
Arrays.fill(bytes, (byte) 'h');

5.3.5. Comparator

1
2
3
4
5
6
7
8
9
10
11
12
13
// --before update
Arrays.sort(ctors, (c1, c2) -> {
int c1pl = c1.getParameterCount();
int c2pl = c2.getParameterCount();
return (c1pl < c2pl ? -1 : (c1pl > c2pl ? 1 : 0));
});

// --after update
Arrays.sort(ctors, (c1, c2) -> {
int c1pl = c1.getParameterCount();
int c2pl = c2.getParameterCount();
return Integer.compare(c1pl, c2pl);
});

Contributor 使用 Integer.compare(int, int) 来简化比较代码。以后比较整数可以使用 Integer.compare(int, int)


5.3.6. 数组克隆

1
2
3
4
5
6
7
// --before update
String[] copy = new String[state.length];
System.arraycopy(state, 0, copy, 0, state.length);
return copy;

// --after update
return state.clone();

5.4. Java注释

备忘源码中注释样式的各种写法,提高注释水平。

5.4.1. 列表

关键词:<ul></ul><li></li>

Java注释样式写法01

5.4.2. 注释中包含代码

关键词:<pre></pre>{@code}

Java注释样式写法02

5.4.3. 注释继承

接口的实现类,使用 {@inheritDoc} 注解,在阅读模式下,显示接口方法中的注释。

inheritDoc注解

5.4.4. 直接引用变量值

关键词:{@value}

Value注解

Value注解

5.4.5. package-info.java

pacakge-info.java 是一个Java文件,可以添加到任何的Java源码包中。pacakge-info.java 的目标是提供一个包级的文档说明或者是包级的注释。

如 spring-boot 源码中的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
* Copyright 2012-2017 the original author or authors.
*
* 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
*
* https://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.
*/

/**
* Core Spring Boot classes.
*
* @see org.springframework.boot.SpringApplication
*/
package org.springframework.boot;

在 IDEA 中 package-info.java 文件不能随便被创建,会出现 This is not a valid Java qualified name
错误,可以通过创建一个普通的文件来变相创建 pacakge-info.java 文件。


5.5. 工具方法

5.5.1. Stream

  • List 转换 Array

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // String
    List<String> list = new ArrayList<>(Arrays.asList("1", "2", "3", "4", "5"));
    String[] array = list.toArray(new String[0]);
    System.out.println(Arrays.toString(array));
    // output: [1, 2, 3, 4, 5]

    // Integer
    List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
    int[] arr = list.stream().mapToInt(Integer::intValue).toArray();
    System.out.println(Arrays.toString(arr));
    // output: [1, 2, 3, 4, 5]
  • Array 转 List

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // String
    String[] arr2 = {"1", "2", "3", "4", "5"};
    List<String> collect = Arrays.stream(arr2).collect(Collectors.toList());
    System.out.println(collect);
    // output: [1, 2, 3, 4, 5]

    // Integer
    int[] arr2 = {1, 2, 3, 4, 5};
    List<Integer> collect = IntStream.of(arr2).boxed().collect(Collectors.toList());
    System.out.println(collect);
    // output: [1, 2, 3, 4, 5]

5.5.2. JSON

  • 字符串数组转换数组

    1
    2
    3
    4
    5
    6
    import com.alibaba.fastjson.JSON;

    String data = "[\"123\",\"456\",\"789\"]";
    String[] toArray = JSON.parseArray(data, String.class).toArray(new String[0]);
    System.out.println("toArray:" + Arrays.toString(toArray));
    // toArray:[123, 456, 789]

5.5.3. Guava

Guava 版本升级兼容性不太好,升级需要谨慎!

  • Collections2.filter: 自定义过滤

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    List<String> list = Arrays.asList(null, "123", "456", "789", "", "112233");
    System.out.println(list); // [null, 123, 456, 789, , 112233]

    // 过滤 null
    Collection<String> collection = Collections2.filter(list, Predicates.notNull());
    System.out.println(collection); // [123, 456, 789, , 112233]

    // 过滤空字符串
    collection = Collections2.filter(list, Predicates.not(StringUtils::isBlank));
    System.out.println(collection); // [123, 456, 789, 112233]

    // 筛选出元素中包含7的
    List<String> list = Arrays.asList("123", "456", "789", "", "112233");
    Collection<String> collection = Collections2.filter(list, Predicates.containsPattern("7"));
    System.out.println(collection); // [789]

    // --------------------

    // 多个过滤条件
    List<String> list = Arrays.asList(null, "123", "456", "789", "", "112233", "");
    Collection<String> collection = Collections2.filter(list,
    Predicates.and(Predicates.not(StringUtils::isBlank), Predicates.containsPattern("7")));
    System.out.println(collection); // [123, 112233]

    List<String> list = Arrays.asList(null, "123", "456", "789", "", "112233", "");
    Collection<String> collection = Collections2.filter(list,
    Predicates.and(Predicates.not(StringUtils::isBlank), Predicates.containsPattern("1|6")));
    System.out.println(collection); // [123, 456, 112233]
  • Ordering.natural:从小到大排序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // int
    List<Integer> data = new ArrayList<>(Arrays.asList(7, 1, 5, 2, 8, 22));
    data.sort(Ordering.natural());
    System.out.println(data);
    // [1, 2, 5, 7, 8, 22]


    // double
    List<Double> data = new ArrayList<>(Arrays.asList(1d, 5d, 2d, 7d, 9.9d, 8d, 22d));
    data.sort(Ordering.natural());
    System.out.println(data);
    // [1.0, 2.0, 5.0, 7.0, 8.0, 9.9, 22.0]


    // date
    // 2020-10-21 22:09:44
    long time3 = 1603289384000L;
    // 2020-10-01 22:09:44
    long time1 = 1601561384000L;
    // 2020-10-02 22:09:44
    long time2 = 1601647784000L;
    List<Date> dates = new ArrayList<>(Arrays.asList(new Date(time2), new Date(time3), new Date(time1)));
    dates.sort(Ordering.natural());
    dates.forEach(date -> System.out.println(DateUtil.Format.formatTime(date)));
    // 2020-10-01 22:09:44、2020-10-02 22:09:44、2020-10-21 22:09:44
  • reverse:从大到小

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // int
    List<Integer> data = new ArrayList<>(Arrays.asList(7,1, 5, 2 , 8, 22));
    data.sort(Ordering.natural().reverse());
    System.out.println(data);
    // [22, 8, 7, 5, 2, 1]


    // double
    List<Double> data = new ArrayList<>(Arrays.asList(1d, 5d, 2d, 7d, 9.9d, 8d, 22d));
    data.sort(Ordering.natural().reverse());
    System.out.println(data);
    // [22.0, 9.9, 8.0, 7.0, 5.0, 2.0, 1.0]


    // date
    // 2020-10-21 22:09:44
    long time3 = 1603289384000L;
    // 2020-10-01 22:09:44
    long time1 = 1601561384000L;
    // 2020-10-02 22:09:44
    long time2 = 1601647784000L;
    List<Date> dates = new ArrayList<>(Arrays.asList(new Date(time2), new Date(time3), new Date(time1)));
    dates.sort(Ordering.natural().reverse());
    dates.forEach(date -> System.out.println(DateUtil.Format.formatTime(date)));
    // 2020-10-21 22:09:44、2020-10-02 22:09:44、2020-10-01 22:09:44

5.5.4. Spring Framework

5.5.4.1. StringUtils

org.springframework.util.StringUtils

方法含义
boolean endsWithIgnoreCase(String str, String suffix)字符串是否以指定内容结束,忽略大小写。
boolean startsWithIgnoreCase(String str, String prefix)字符串是否以指定内容开头,忽略大小写。
boolean containsWhitespace(CharSequence str)字符串中是否包含空白、空格字符
boolean substringMatch(CharSequence str, int index, CharSequence substring)字符串指定索引处是否包含一个子串
int countOccurrencesOf(String str, String sub)字符串中指定子串出现的次数
String delete(String inString, String pattern)从字符串中删除所有出现的子串
String[] trimArrayElements(String[] array)对数组中的每个元素执行trim()方法
String uriDecode(String source, Charset charset)对URL字符串解码
String getFilenameExtension(String path)解析出文件后缀名
String stripFilenameExtension(String path)删除文件路径名中的后缀部分
String trimTrailingCharacter(String str, char trailingCharacter)去除尾部的特定字符
String trimLeadingCharacter(String str, char leadingCharacter)去除头部的特定字符
String trimAllWhitespace(String str)删除开头、结尾和中间的空白符

5.5.4.2. ClassUtils

org.springframework.util.ClassUtils

方法含义
String getPackageName(String fqClassName)确定给定类的包名称。
String getPackageName(Class<?> clazz)确定给定完全限定类名的包名称。

5.5.5. sun(JDK)

  • ORBUtility.compareVersion: 比较两个字符串版本号。

    如果v1大于、等于或小于v2,则返回1、0或-1。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    String version = "5.1.6.RELEASE";

    int i = ORBUtility.compareVersion("5.4.6.RELEASE", version);
    System.out.println(i); // 1

    i = ORBUtility.compareVersion("5.1.6.RELEASE", version);
    System.out.println(i); // 0

    i = ORBUtility.compareVersion("4.1.6.RELEASE", version);
    System.out.println(i); // -1

    i = ORBUtility.compareVersion("4.1.6.release", version);
    System.out.println(i); // -1

5.5.5.1. Collections

java.util.Collections

方法含义
<T> Set<T> unmodifiableSet(Set<? extends T> s)获取一个不可修改的 Set 集合。
如果试图修改这个集合时,就会抛出 UnsupportedOperationException 异常。


5.6. JVM

5.6.1. import 避免使用通配符

当代码中出现 import xxx.* 时,Java虚拟机会加载 xxx 包下的所有类到 MetaSpace(Java 8+) 或者 PermGen(Java 8之前) 区域中,哪怕这些类在当前代码中并没有被使用,从而浪费内存空间。


5.7. SpringBoot

5.7.1. 配置

项目开发时会把一些变量放到yml配置文件中,例如下面这样:

1
2
3
4
5
6
# application.yml
developer:
name: ccc
websit: 'https://baidu.com'
qq: 875292002
phoneName: 148373639877

使用 @ConfigurationProperties 代替 @Value

1
2
3
4
5
6
7
8
9
@Data
@ConfigurationProperties(prefix = "developer") // 指定前缀
@Component
public class DeveloperProperty {
private String name;
private String website;
private String qq;
private String phoneNumber;
}

需要使用时,注入 DeveloperProperty:

1
2
3
4
5
6
7
8
9
10
11
@RestController
@RequiredArgsConstructor
public class PropertyController {

final DeveloperProperty developerProperty;

@GetMapping("/property")
public Object index() {
return developerProperty.getName();
}
}

Spring 注入 Bean 有三种方式:set注入、构造器注入、注解注入。Spring 推荐使用构造器的方式注入 Bean。

@RequiredArgsConstructor 注解由 lombok 提供,用于代替 @Autowired,编译后如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
public class PropertyController {

final DeveloperProperty developerProperty;

@GetMapping("/property")
public Object index() {
return developerProperty.getName();
}

public PropertyController(DeveloperProperty developerProperty){
this.developerProperty = developerProperty;
}
}

6. Data Structures

Data Structures