Java代码段查阅

集合处理

List集合拼接成以逗号分隔的字符串

  1. list.stream().collect(Collectors.joining(","));
  2. String.join(",", list)

两个List集合取交集

  • list1.retainAll(list2)

交集、并集、差集

1
2
3
4
5
6
/*交集*/
List<AClass> intersectResult = aClassList1.stream().filter(aClassList2::contains).collect(Collectors.toList());
/*并集*/
Stream.of(list1, list2).flatMap(Collection::stream).collect(Collectors.toList());
/*差集*/
List<AClass> differenceResult = aClassList1.stream().filter(x -> !aClassList2.contains(x)).collect(Collectors.toList());

使用parallelStream时要注意线程安全问题

  • 在并发时使用HashMap和ArrayList等非线程安全的类是会存在问题的
  • 应使用
    1. list合并:
      1
      2
      3
      4
      Stream.of().parallel()
      .mapToObj(index -> {
      return Collections.<T>emptyList();
      }).flatMap(Collection::stream).collect(Collectors.toList());
    2. map合并:
      1
      2
      3
      4
      5
      6
      Stream.of().parallel()
      .mapToObj(index -> {
      return Collections.<K, V>emptyMap();
      })
      .flatMap(x -> x.entrySet().stream())
      .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1));

排序

  • list.sort(Comparator.comparing(XXX::getXX, Comparator.reverseOrder()).thenComparing(XXX::getXXX))
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    list.sort(
    Comparator.comparing((Function<XXXBO, Integer>)xxxBO -> {
    if (ids.contains(xxxBO.getId())) {
    return 0;
    }
    return 1;
    }).thenComparing(xxxBO -> {
    if (ptIds.contains(xxxBO.getTId())) {
    return 0;
    }
    return 1;
    })
    .thenComparing(XXXBO::getAddTime, Comparator.reverseOrder())
    .thenComparing(XXXBO::getId, Comparator.reverseOrder()));

字符串

首字母转成大写

  • StringUtils.capitalize(str);

重复拼接字符串

  • StringUtils.repeat("ab", 2);

字符串分割

1
2
3
4
5
6
7
Iterable<String> split = Splitter.on(',')
.trimResults()
.omitEmptyStrings()
.split(sourceStr);
return Sets.newHashSet(split)

Sets.newHashSet(Splitter.on(",").omitEmptyStrings().trimResults().splitToList(topics));

日期

Date类型转String类型

  • String date = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");

String类型转Date类型

  • Date date = DateUtils.parseDate("2021-05-01 01:01:01", "yyyy-MM-dd HH:mm:ss");

计算一个小时后的日期

  • Date date = DateUtils.addHours(new Date(), 1);

java8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
long tomorrowZeroTime = LocalDate.now().plusDays(1).atTime(LocalTime.MIN).atZone(ZoneId.systemDefault()).toEpochSecond();
long days = (expireZeroTime - nowZeroTime) / SECONDS_PER_DAY;
long beginTime = LocalDateTime.now().plusHours(-2).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
long endTime = LocalDateTime.now().plusHours(-1).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
long exportStartTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN).minusDays(1).atZone(ZoneId.systemDefault()).toEpochSecond();
long exportStartTime =LocalDateTime.now().withHours(0).plusHours(-1).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
Long millisecond = Instant.now().toEpochMilli(); // 精确到毫秒
Long second = Instant.now().getEpochSecond();// 精确到秒
LocalDateTime.ofInstant(Instant.ofEpochMilli(time),ZoneId.systemDefault())
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate dt = LocalDate.parse("20191020", formatter);
dt.plusDays(1);
String day = dt.format(formatter);
//Java8的DateTimeFormatter是线程安全的,而SimpleDateFormat并不是线程安全。

开源库

commons-collections4

1
2
3
4
5
6
// 两个集合取交集
Collection<String> collection = CollectionUtils.retainAll(listA, listB);
// 两个集合取并集
Collection<String> collection = CollectionUtils.union(listA, listB);
// 两个集合取差集
Collection<String> collection = CollectionUtils.subtract(listA, listB);

common-beanutils 操作对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
User user = new User();
BeanUtils.setProperty(user, "id", 1);
BeanUtils.setProperty(user, "name", "yideng");
System.out.println(BeanUtils.getProperty(user, "name")); // 输出 yideng
System.out.println(user); // 输出 {"id":1,"name":"yideng"}
对象和map互转

// 对象转map
Map<String, String> map = BeanUtils.describe(user);
System.out.println(map); // 输出 {"id":"1","name":"yideng"}
// map转对象
User newUser = new User();
BeanUtils.populate(newUser, map);
System.out.println(newUser); // 输出 {"id":1,"name":"yideng"}

commons-io 文件流处理

1
2
3
4
5
6
7
8
9
10
File file = new File("demo1.txt");
// 读取文件
List<String> lines = FileUtils.readLines(file, Charset.defaultCharset());

FileUtils.readFileToString(new File("xxx"));
// 写入文件
FileUtils.writeLines(new File("demo2.txt"), lines);
// 复制文件
FileUtils.copyFile(srcFile, destFile);

Google Guava 工具类库

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//创建集合
List<String> list = Lists.newArrayList();
List<Integer> list = Lists.newArrayList(1, 2, 3);
// 反转list
List<Integer> reverse = Lists.reverse(list);
System.out.println(reverse); // 输出 [3, 2, 1]
// list集合元素太多,可以分成若干个集合,每个集合10个元素
List<List<Integer>> partition = Lists.partition(list, 10);

Map<String, String> map = Maps.newHashMap();
Set<String> set = Sets.newHashSet();

//Multimap 一个key可以映射多个value的HashMap
Multimap<String, Integer> map = ArrayListMultimap.create();
map.put("key", 1);
map.put("key", 2);
Collection<Integer> values = map.get("key");
System.out.println(map); // 输出 {"key":[1,2]}
// 还能返回你以前使用的臃肿的Map
Map<String, Collection<Integer>> collectionMap = map.asMap();

//BiMap 一种连value也不能重复的HashMap
BiMap<String, String> biMap = HashBiMap.create();
// 如果value重复,put方法会抛异常,除非用forcePut方法
biMap.put("key","value");
System.out.println(biMap); // 输出 {"key":"value"}
// 既然value不能重复,何不实现个翻转key/value的方法,已经有了
BiMap<String, String> inverse = biMap.inverse();
System.out.println(inverse); // 输出 {"value":"key"}

//Table 一种有两个key的HashMap
// 一批用户,同时按年龄和性别分组
Table<Integer, String, String> table = HashBasedTable.create();
table.put(18, "男", "yideng");
table.put(18, "女", "Lily");
System.out.println(table.get(18, "男")); // 输出 yideng
// 这其实是一个二维的Map,可以查看行数据
Map<String, String> row = table.row(18);
System.out.println(row); // 输出 {"男":"yideng","女":"Lily"}
// 查看列数据
Map<Integer, String> column = table.column("男");
System.out.println(column); // 输出 {18:"yideng"}
// Multiset 一种用来计数的Set
Multiset<String> multiset = HashMultiset.create();
multiset.add("apple");
multiset.add("apple");
multiset.add("orange");
System.out.println(multiset.count("apple")); // 输出 2
// 查看去重的元素
Set<String> set = multiset.elementSet();
System.out.println(set); // 输出 ["orange","apple"]
// 还能查看没有去重的元素
Iterator<String> iterator = multiset.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// 还能手动设置某个元素出现的次数
multiset.setCount("apple", 5);

其他

比较两个对象是否相等

  • Objects.equals(strA, strB); (防止空指针)

异步

1.

1
2
3
CompletableFuture.supplyAsync(
() -> {
});

2.

1
2
CompletableFuture.runAsync(() -> {
});

重写toString

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this,
ToStringStyle.SHORT_PREFIX_STYLE);
}

@Override
public String toString() {
ReflectionToStringBuilder builder = new ReflectionToStringBuilder(
this, ToStringStyle.SHORT_PREFIX_STYLE) {
@Override
protected boolean accept(Field field) {
return !"createTime".equals(field.getName()) &&
!field.getName().equals("updateTime") &&
!field.getName().equals("xxx");
}
};
return builder.toString();
}

Stream

1
2
3
4
5
6
Map<String, String> requestMap =
request.getParameterMap().entrySet().stream().collect(
Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue()[0], (v1, v2) -> {
throw new RuntimeException(String.format("Duplicate key for values %s and %s", v1, v2));
},
TreeMap::new));

Optional

1
.orElseThrow(() -> new ContextedRuntimeException("notExist").addContextValue("id", id));

Optional中map和flatMap

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
29
30
31
32
33
class FlightTicketInfo {

private String orderNumber;

public String getOrderNumber() {
return orderNumber;
}

}

/**
* desc :
* create_user : cheng
* create_date : 2018/7/4 11:21
*/
public class OptionalTest {

@Test
public void testMap() {
FlightTicketInfo flightTicketInfo = null;

Optional<Optional<String>> s1 = Optional.ofNullable(flightTicketInfo).map(OptionalTest::getOrderNumber);

Optional<String> s2 = Optional.ofNullable(flightTicketInfo).map(FlightTicketInfo::getOrderNumber);

Optional<String> s3 = Optional.ofNullable(flightTicketInfo).flatMap(OptionalTest::getOrderNumber);
}

private static Optional<String> getOrderNumber(FlightTicketInfo flightTicketInfo) {
return Optional.ofNullable(flightTicketInfo).map(f -> f.getOrderNumber());
}

}
  • 1.9新增 or()方法是作为orElse()和orElseGet()方法的改进而出现的,使用方法一致,但后两个方法在执行完成后返回的并非包装值。如果需要执行一些逻辑并返回Optional时,可以使用or()方法。该方法传入Supplier接口的实例,当value有值时直接返回自身Optional,当为空时,自动执行suuplier的get()方法,并包装成Optional返回,其源码中包装的语句如下:
1
2
Optional<T> r = (Optional<T>) supplier.get();
return Objects.requireNonNull(r);
  • stream()方法则不用多说,是一个提供给流式编程使用的方法,功能上是一个适配器,将Optional转换成Stream:没有值返回一个空的stream,或者包含一个Optional的stream。其源码如下:
1
2
3
4
5
if (!isPresent()) {
return Stream.empty();
} else {
return Stream.of(value);
}
  • 其原因是orElseGet()的参数是Supplier目标类型的函数,简单来说,Suppiler接口类似Spring的懒加载,声明之后并不会占用内存,只有执行了get()方法之后,才会调用构造方法创建出对象,而orElse()是快加载,即使没有调用,也会实际的运行。
    这个特性在一些简单的方法上差距不大,但是当方法是一些执行密集型的调用时,比如远程调用,计算类或者查询类方法时,会损耗一定的性能。
    orElseThrow()方法与orElseGet()方法的参数都是Supplier参数都是函数类型的,这意味着这两种方法都是懒加载,但针对于必须要使用异常控制流程的场景,orElseThrow()会更加合适,因为可以控制异常类型,使得相比NPE会有更丰富的语义。

BigDecimal

  • user.getMoney().stripTrailingZeros().toPlainString()
1
2
3
4
5
6
public BigDecimal sum(Function<XXX, BigDecimal> get, List<XXX> list) {
return list.stream().map(get).reduce((acc, item) -> {
acc = acc.add(item);
return acc;
}).get().divide(BigDecimal.valueOf(100));
}

包装临时对象

  • 当一个方法需要返回两个及以上字段时,可以使用Pair和Triple
  • 返回两个字段
    ImmutablePair<Integer, String> pair = ImmutablePair.of(1, "yideng");
  • 返回三个字段
    ImmutableTriple<Integer, String, Date> triple = ImmutableTriple.of(1, "yideng", new Date());

临时文件返回

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@RestController
public class XXXController {

@GetMapping(value = "/xxdata.txt")
public void bidata(HttpServletResponse response) {

String content = "success|=|333\nsuccess|=|333";
try {
response.setHeader("Content-Type", "text/plain;charset=utf-8");
response.addHeader("Content-Disposition","attachment;filename=xxdata.txt");
OutputStream output = response.getOutputStream();
output.write(content.getBytes(Charset.forName("UTF-8")));
output.flush();
} catch (Exception e) {
e.printStackTrace();
}
}

@GetMapping(value = "/xxdata.txt")
public String bidata(HttpServletResponse response) {

response.setHeader("Content-Type", "text/plain;charset=utf-8");
response.addHeader("Content-Disposition","attachment;filename=xxdata.txt");
return "success|=|333\nsuccess|=|333";

}

@GetMapping(value = "/xxvideo/{uri}")
public void proxy(@PathVariable("uri") String uri, HttpServletResponse response) {
try {

response.setHeader("Access-Control-Allow-Origin", "*.xx.cn, *.xx.xx.com");

OutputStream output = response.getOutputStream();
String url = xxxService.getRealUrl(uri);

if (StringUtils.isBlank(url)) {
response.setStatus(HttpStatus.NOT_FOUND_404);
return;
}
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(forwardProxyHost, forwardProxyPort));
try (InputStream input = new URL(url).openConnection(proxy).getInputStream()) {
IOUtils.copy(input, output);
} finally {
}
} catch (Exception e) {
LOGGER.error("error,uri:{}", uri, e);
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500);
}
}
}

线程池

1
ExecutorService executor = new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 2, new BasicThreadFactory.Builder().namingPattern("common-schedule-pool-%d").daemon(true).build()); 

扫描注解

1
2
3
4
5
6
7
8
9
10

Reflections reflections = new Reflections(new ConfigurationBuilder()
.addUrls(ClasspathHelper.forPackage("com.xxx"))
.setScanners(new MethodAnnotationsScanner()));

for (final Method method : reflections.getMethodsAnnotatedWith(xxxxx.class)) {
Class<?> clazz = method.getDeclaringClass();
Collection<?> beans = applicationContext.getBeansOfType(clazz).values();
int size = beans.size();
}
1
2
3
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.11</version>

并发

1
2
3
4
5
 CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
return true;
});
CompletableFuture<Boolean> future2 = CompletableFuture.supplyAsync(() -> true);
CompletableFuture<Boolean> future3 = CompletableFuture.supplyAsync(() -> true);
1
2
3
4
5
6
7
8
9
List<Supplier<Boolean>> tasks = new ArrayList<>(2);
tasks.add(() -> {
return true;
});

tasks.add(() -> {
return true;
});
tasks.stream().parallel().forEach(Supplier::get);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
CompletableFuture<CallResult> future1 = CompletableFuture.supplyAsync(() -> {
return CallResult.FAIL;
});

CompletableFuture<CallResult> future2 = CompletableFuture.supplyAsync(() -> {
return CallResult.FAIL;
});

List<CallResult> resultList = Stream.of(future1, future2).map(CompletableFuture::join).collect(
Collectors.toList());

if (resultList.stream().filter(v -> CallResult.FAIL.equals(v)).count() > 0) {
throw new Exception(" call exception");
}
1
2
3
return IntStream.range(0, DBTableConfig.SIZE).parallel()
.mapToObj(index -> mapper.selectAllList(index, Date.from(Instant.ofEpochSecond(startTime)),
Date.from(Instant.ofEpochSecond(endTime)), xxx, Arrays.asList(xx, xx), limit)).flatMap(Collection::stream).collect(Collectors.toList());
1
2
3
4
5
6
7
8
9
CompletableFuture<Void> cf6 = CompletableFuture.allOf(cf3, cf4, cf5);
CompletableFuture<String> result = cf6.thenApply(v -> {
//这里的join并不会阻塞,因为传给thenApply的函数是在CF3、CF4、CF5全部完成时,才会执行 。
result3 = cf3.join();
result4 = cf4.join();
result5 = cf5.join();
//根据result3、result4、result5组装最终result;
return "result";
});

开源类库

  • apache commons
  • commons-lang3
  • commons-collections

Web

1
2
3
4
5
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    /**
* curl -XPOST -F "materialFile=@/D:/Downloads/5c1.FBX" "http://127.0.0.1:19201/addMaterial"
* @param materialFile
* @return
*/
@CheckToken(false)
@PostMapping("/addMaterial")
public ApplicationResponse addMaterial(@RequestParam("materialFile") MultipartFile materialFile
) {
return ApplicationResponse.ok().build();
}

spring.http.multipart.maxFileSize=10MB
spring.http.multipart.maxRequestSize=10MB
  • long 前端失精问题
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Bean("jackson2ObjectMapperBuilderCustomizer")
    @ConditionalOnProperty(name = "config.long2string", havingValue = "true", matchIfMissing = true)
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
    Jackson2ObjectMapperBuilderCustomizer customizer = new Jackson2ObjectMapperBuilderCustomizer() {
    @Override
    public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
    jacksonObjectMapperBuilder.serializerByType(Long.class, ToStringSerializer.instance)
    .serializerByType(Long.TYPE, ToStringSerializer.instance);
    }
    };
    return customizer;
    }

MyBatis

1
2
3
4
5
6
7
8
9
10
11
12
13
<select id="queryBookInfo" parameterType="com.tjt.platform.entity.BookInfo" resultType="java.lang.Integer">
select count(*) from t_rule_BookInfo t
<where>
<if test="title !=null and title !='' ">
title = #{title}
</if>
<if test="author !=null and author !='' ">
AND author = #{author}
</if>
</where>
</select>

UPDATE 操作也一样,可以用标记代替 1=1。
1
2
3
4
5
6
7
8
9
10
11
12
13
@Select({
"<script>",
"SELECT " + FIELDS,
"FROM `t_xxxx_task` t",
"WHERE createTime &gt;= #{startTime} AND createTime &lt; #{endTime} ",
"<when test = 'statusList != null and statusList.size > 0'>",
"AND `status` in (<foreach collection = 'statusList' item = 'status' index='index' open='' close='' separator=','>#{status}</foreach>)",
"</when>",
"LIMIT #{limit}",
"</script>"
})
List<TxxxxTask> selectList(@Param("startTime")Date startTime, @Param("endTime")Date endTime, @Param("statusList") List<Integer> statusList, @Param("limit") int limit);

Reference