Apache-Commons-*
字串
判斷字串是否為空白字串
以前判斷字串是否為空:
if ((name == null) || (name.isEmpty())){}
使用 apache-common-lang3 的 StringUtils:
void testIsBlank() {
// true
Assertions.assertTrue(StringUtils.isBlank(" "));
// true
Assertions.assertTrue(StringUtils.isBlank(""));
// true
Assertions.assertTrue(StringUtils.isBlank(null));
// false
Assertions.assertFalse(StringUtils.isBlank("foo"));
// true
Assertions.assertTrue(StringUtils.isAnyBlank(null, " "));
// false
Assertions.assertFalse(StringUtils.isAnyBlank("foo", " bar "));
}
左邊填充字串
有時候我們需要生成流水號,例如4位數的流水號,從1開始其余用字符'0'填充,就可以使用 leftPad 方法,示例如下:
@Test
void testLeftPad() {
// 0001
Assertions.assertEquals("0001", StringUtils.leftPad("1", 4, '0'));
}
右邊填充字串
@Test
void testRightPad() {
// 1000
Assertions.assertEquals("1000", StringUtils.rightPad("1", 4, '0'));
}
分割字串
// ["a","b","c"]
Assertions.assertEquals(Arrays.toString(new String[]{"a", "b", "c"}), Arrays.toString(StringUtils.split("a,b,c", ",")));
字串比較
// true
Assertions.assertTrue(StringUtils.equals(null, null));
// false
Assertions.assertFalse(StringUtils.equals("null", null));
字串已指定子字串開頭
@Test
void testStartWith() {
// true
Assertions.assertTrue(StringUtils.startsWith("hello,world", "hello"));
// false
Assertions.assertFalse(StringUtils.startsWith("你好,世界", "世界"));
}
數值工具類
轉換為 int 型別
將字串轉換為 int 型別,toInt(String str) 在轉換失敗的時候會回傳默認值 0,如果需要指定默認值那么可以使用 toInt(final String str, final int defaultValue):
@Test
void testToInt() {
// 0
Assertions.assertEquals(0, NumberUtils.toInt("abc"));
// 0
Assertions.assertEquals(0, NumberUtils.toInt("01c"));
// 0
Assertions.assertEquals(0, NumberUtils.toInt("1a3"));
// 1
Assertions.assertEquals(1, NumberUtils.toInt("foo", 1));
// 11
Assertions.assertEquals(11, NumberUtils.toInt("11"));
// 11
Assertions.assertEquals(11, NumberUtils.toInt("011", 3));
}
陣列
判斷陣列是否為空
@Test
void testIsEmpty() {
// true
Assertions.assertTrue(ArrayUtils.isEmpty(new Object[]{}));
// false
Assertions.assertFalse(ArrayUtils.isEmpty(new String[]{"foo"}));
}
日期
增加指定天數
除了增加指定的天數,common-lang3 還提供了:
addHours:增加指定小時addMonths:增加指定月數- 等...
@Test
void testAddDay() {
Date now = new Date();
Date tomorrow = DateUtils.addDays(now, 1);
Assertions.assertEquals(1, Duration.ofMillis(tomorrow.getTime() - now.getTime()).toDays());
Assertions.assertEquals(Duration.ofDays(1).toMillis(), Duration.ofMillis(tomorrow.getTime() - now.getTime()).toMillis());
}
格式化日期
tring pattern = "yyyy-MM-dd HH:mm:ss";
Date d1 = DateUtils.parseDate("2022-10-22 00:00:00", pattern);
Assertions.assertEquals("2022-10-22 00:00:00", DateFormatUtils.format(d1, pattern));
判斷是否為同一天
String parsePattern = "yyyy-MM-dd HH:mm:ss";
Date d1 = DateUtils.parseDate("2022-10-22 00:00:00", parsePattern);
Date d2 = DateUtils.parseDate("2022-10-22 23:59:59", parsePattern);
// true
Assertions.assertTrue(DateUtils.isSameDay(d1, d2));
d1 = DateUtils.parseDate("2022-10-23 00:00:00", parsePattern);
d2 = DateUtils.parseDate("2022-10-22 00:00:00", parsePattern);
// false
Assertions.assertFalse(DateUtils.isSameDay(d1, d2));
列舉
@Test
void testGetEnum() {
Assertions.assertThrowsExactly(IllegalArgumentException.class, () -> Season.valueOf("Spring"));
// 默認回傳null,不拋出例外
Assertions.assertNull(EnumUtils.getEnum(Season.class, "spring"));
// 指定默認值
Assertions.assertEquals(Season.SPRING, EnumUtils.getEnumIgnoreCase(Season.class, "spring"));
// 忽略大小寫匹配
Assertions.assertEquals(Season.SPRING, EnumUtils.getEnum(Season.class, "spring", Season.SPRING));
}
enum Season {
SPRING,
}
Guava
分割字串
在了解 Guava 提供的字串分割器之前,我們先來看看 Java 提供的字串分隔有什么缺點,如下所示,輸出的結果為:
",a,,b,".split(",")
"", "a", "", "b", ""null, "a", null, "b", null"a", null, "b""a", "b"- 以上都不對
正確輸出結果是 [, a, , b],答案是選項5:“以上都不對”,Splitter 不僅實作了字串分隔,還提供了對應的修飾符,即對拆分結果進行處理,例如:
String str = "foo, bar ,,,baz";
// ["foo","bar","baz"]
Splitter.on(",")
.trimResults()
.omitEmptyStrings()
.splitToList(str);
// [上下上下左, 左, 右右]
str = "baba上下上下左a左b右右";
res = Splitter.on(CharMatcher.inRange('a', 'b'))
.trimResults()
.omitEmptyStrings()
.splitToList(str);
// [上下上下左, 左, 右右]
log.info("{}", res);
拆分器工廠
| 方法 | 描述 | 示例 |
|---|---|---|
Splitter.on(char) |
按單個字符拆分 | Splitter.on(','); |
Splitter.on(CharMatcher) |
按字符匹配器拆分 | Splitter.on(CharMatcher.inRange('a', 'b')) |
Splitter.on(String) |
按字串拆分 | Splitter.on(", ") |
Splitter.on(Pattern)或onPattern(String) |
按正則運算式拆分 | Splitter.on("\r?\n ") |
Splitter.fixedLength(int) |
按固定長度拆分;最后一段可能比給定長度短,但不會為空, | Splitter.fixedLength(3) |
拆分器修飾符
| 方法 | 描述 |
|---|---|
omitEmptyStrings() |
從結果中自動忽略空白字串 |
trimResults() |
移除結果字串的首位空白字符 |
trimResults(CharMatcher) |
給定匹配器,移除結果字串的首位匹配字符 |
limit(int) |
限制拆分出的字串數量 |
不可變集合
public static final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of(
"red",
"orange",
"yellow",
"green",
"blue",
"purple");
class Foo {
Set<Bar> bars;
Foo(Set<Bar> bars) {
this.bars = ImmutableSet.copyOf(bars); // defensive copy!
}
}
不可變物件有很多的優點:
- 當物件被不可信的庫呼叫時,不可變形式是安全的;
- 不可變物件被多個執行緒呼叫時,不存在競態條件問題
- 不可變集合不需要考慮變化,因此可以節省時間和空間,所有不可變的集合都比它們的可變形式有更好的記憶體利用率(分析和測驗細節);
- 不可變物件因為有固定不變,可以作為常量來安全使用,
使用不可變集合
不可變集合可以用如下多種方式創建:
copyOf:ImmutableList.copyOfof:ImmutableList.of("a","b","c")Builder工具,例如:
public static final ImmutableSet<Color> GOOGLE_COLORS =
ImmutableSet.<Color>builder()
.addAll(WEBSAFE_COLORS)
.add(new Color(0, 191, 255))
.build();
連接字串
@Test
void testJoin() {
// foo,bar
Assertions.assertEquals("foo,bar", Joiner.on(',').join(ImmutableList.of("foo", "bar")));
// foo
Assertions.assertEquals("foo", Joiner.on(',').skipNulls().join("foo", null));
// foo,empty
Assertions.assertEquals("foo,empty", Joiner.on(',').useForNull("empty").join("foo", null));
// 拋出空指標例外
Assertions.assertThrowsExactly(NullPointerException.class, () -> Joiner.on(',').join("foo", null));
}
警告:joiner實體總是不可變的,用來定義joiner目標語意的配置方法總會回傳一個新的joiner實體,這使得joiner實體都是執行緒安全的,你可以將其定義為static final常量,
Strings
將 null 轉換為空字串:
Assertions.assertEquals("", Strings.nullToEmpty(null));
將空字串轉換為 null :
Assertions.assertEquals(null, Strings.emptyToNull(""));
Assertions.assertEquals(null, Strings.emptyToNull(null));
CharMatcher
String noControl = CharMatcher.JAVA_ISO_CONTROL.removeFrom(string); //移除control字符
String theDigits = CharMatcher.DIGIT.retainFrom(string); //只保留數字字符
String spaced = CharMatcher.WHITESPACE.trimAndCollapseFrom(string, ' ');
//去除兩端的空格,并把中間的連續空格替換成單個空格
String noDigits = CharMatcher.JAVA_DIGIT.replaceFrom(string, "*"); //用*號替換所有數字
String lowerAndDigit = CharMatcher.JAVA_DIGIT.or(CharMatcher.JAVA_LOWER_CASE).retainFrom(string);
// 只保留數字和小寫字母
Spring
判斷集合是否為空
@Test
void testIsEmpty() {
Assertions.assertTrue(CollectionUtils.isEmpty((List<?>) null));
Assertions.assertTrue(CollectionUtils.isEmpty((Set<?>) null));
Assertions.assertTrue(CollectionUtils.isEmpty((Map<?, ?>) null));
Assertions.assertTrue(CollectionUtils.isEmpty(Collections.emptyList()));
Assertions.assertTrue(CollectionUtils.isEmpty(Collections.emptySet()));
Assertions.assertTrue(CollectionUtils.isEmpty(Collections.emptyMap()));
Assertions.assertTrue(CollectionUtils.isEmpty(List.of()));
Assertions.assertTrue(CollectionUtils.isEmpty(Set.of()));
Assertions.assertTrue(CollectionUtils.isEmpty(Map.of()));
List<Object> list = new LinkedList<>();
list.add(new Object());
Assertions.assertFalse(CollectionUtils.isEmpty(list));
Assertions.assertFalse(CollectionUtils.isEmpty(List.of("foo")));
Map<String, String> map = new HashMap<>();
map.put("foo", "bar");
Assertions.assertFalse(CollectionUtils.isEmpty(map));
Assertions.assertFalse(CollectionUtils.isEmpty(Map.of("foo", "bar")));
}
獲取集合的第一個元素
@Test
void testFirstElement() {
Assertions.assertNull(CollectionUtils.firstElement((Set<?>) null));
Assertions.assertNull(CollectionUtils.firstElement((List<?>) null));
List<String> list = new ArrayList<>();
list.add(null);
// null
Assertions.assertNull(CollectionUtils.firstElement(list));
list = new ArrayList<>();
list.add("foo");
// foo
Assertions.assertEquals("foo", CollectionUtils.firstElement(list));
list = List.of("foo", "bar");
// foo
Assertions.assertEquals("foo", CollectionUtils.firstElement(list));
Set<String> set = new TreeSet<>();
set.add("b");
set.add("a");
// a
Assertions.assertEquals("a", CollectionUtils.firstElement(set));
// b
set = new TreeSet<>(Comparator.reverseOrder());
set.add("b");
set.add("a");
Assertions.assertEquals("b", CollectionUtils.firstElement(set));
}
獲取集合的最后一個元素
@Test
void testLastElement() {
Assertions.assertNull(CollectionUtils.lastElement((Set<?>) null));
Assertions.assertNull(CollectionUtils.lastElement((List<?>) null));
List<String> list = new ArrayList<>();
list.add(null);
Assertions.assertNull(CollectionUtils.lastElement(list));
list = new ArrayList<>();
list.add("foo");
list.add("bar");
// bar
Assertions.assertEquals("bar", CollectionUtils.lastElement(list));
list = List.of("foo", "bar");
Assertions.assertEquals("bar", CollectionUtils.lastElement(list));
Set<String> set = new TreeSet<>();
set.add("b");
set.add("a");
// b
Assertions.assertEquals("b", CollectionUtils.lastElement(set));
set = new TreeSet<>(Comparator.reverseOrder());
set.add("b");
set.add("a");
// a
Assertions.assertEquals("a", CollectionUtils.lastElement(set));
}
物件屬性拷貝
添加一個測驗物件:
class User {
private String name;
private String email;
// 忽略getXxx和setXxx方法
@Test
void testCopyProperties() {
User user = new User();
user.setName("foo");
user.setEmail("bar");
User target = new User();
// 拷貝屬性
BeanUtils.copyProperties(user, target, "email");
Assertions.assertEquals("foo", target.getName());
Assertions.assertNull(target.getEmail());
}
命名的 ThreadLocal
@Test
void testNamedThreadLocal() {
NamedThreadLocal<String> threadLocal = new NamedThreadLocal<>("task");
Assertions.assertEquals("task", threadLocal.toString());
}
判斷物件是否相等
@Test
void testNullSafeEquals() {
Assertions.assertTrue(ObjectUtils.nullSafeEquals(null, null));
Assertions.assertTrue(ObjectUtils.nullSafeEquals("a", "a"));
Assertions.assertTrue(ObjectUtils.nullSafeEquals(Optional.of("a"), Optional.of("a")));
}
判斷物件是否為空
@Test
void testIsEmpty() {
Assertions.assertTrue(ObjectUtils.isEmpty((Object) null));
Assertions.assertTrue(ObjectUtils.isEmpty(Optional.empty()));
Assertions.assertTrue(ObjectUtils.isEmpty(""));
Assertions.assertTrue(ObjectUtils.isEmpty(new String[]{}));
Assertions.assertTrue(ObjectUtils.isEmpty(Collections.emptyList()));
Assertions.assertTrue(ObjectUtils.isEmpty(Collections.emptyMap()));
}
資源工具類
有時候我們需要加載 classpath 目錄下的資源,例如:
File file = new File(ResourceUtilsTests.class.getClassLoader().getResource("log4j2.xml").toURI());
Assertions.assertEquals("log4j2.xml", file.getName());
使用 Spring 的 ResourceUtils 只需要這么寫:
File file = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + "log4j2.xml");
Assertions.assertEquals("log4j2.xml", file.getName());
計時器
@Test
void testStopWatch() throws InterruptedException {
// 創建一個計時器(秒表)
StopWatch stopWatch = new StopWatch();
// 開始計時
stopWatch.start();
Thread.sleep(Duration.ofSeconds(1).toMillis());
// 停止計時
stopWatch.stop();
// 獲取總耗時(毫秒)
// 1005ms.
log.info("{}ms.", stopWatch.getTotalTimeMillis());
// 1s.
log.info("{}s.", Duration.ofMillis(stopWatch.getTotalTimeMillis()).toSeconds());
}
UriComponentsBuilder
有時候我們需要在服務端手動發送請求,在請求 url 我們使用字串拼接的方式,Spring 提供了UriComponentsBuilder 能讓我們更加語意化來構建一個請求url,而且還會自動對url進行編碼:
@Test
void testFromUriString() {
String uri = UriComponentsBuilder
.fromUriString("/coffee/{foo}/{id}/like")
.build("aa", "bb")
.toString();
Assertions.assertEquals("/coffee/aa/bb/like", uri);
uri = UriComponentsBuilder
.fromUriString("http://localhost:8080/coffe/{id}")
.encode()
.build(1).toString();
Assertions.assertEquals("http://localhost:8080/coffe/1", uri);
uri = UriComponentsBuilder
.fromUriString("http://localhost:8080/coffee?name={name}")
.build(" ").toString();
Assertions.assertEquals("http://localhost:8080/coffee?name=%20",uri);
}
hutool
校驗
@Test
void testIsCitizenId() {
// 校驗是否為身份證
Assertions.assertTrue(Validator.isCitizenId("110101199003074477"));
// 15位身份證號碼驗證
Assertions.assertTrue(Validator.isCitizenId("410001910101123"));
// 10位身份證號碼驗證
Assertions.assertTrue(Validator.isCitizenId("U193683453"));
}
@Test
void testIsMobile() {
// 校驗是否為手機號
Assertions.assertTrue(Validator.isMobile("13900221432"));
Assertions.assertTrue(Validator.isMobile("015100221432"));
Assertions.assertTrue(Validator.isMobile("+8618600221432"));
}
@Test
void testIsPlateNumber() {
// 校驗是否為車牌號
Assertions.assertTrue(Validator.isPlateNumber("粵BA03205"));
Assertions.assertTrue(Validator.isPlateNumber("閩20401領"));
}
emoji
@Test
void testToUnicode() {
String unicode = EmojiUtil.toUnicode(":smile:");
Assertions.assertEquals("??", unicode);
}
@Test
void testToAlias() {
Assertions.assertEquals(":smile:", EmojiUtil.toAlias("??"));
}
@Test
void testToHtml() {
String html = EmojiUtil.toHtml("??");
Assertions.assertEquals("😄", html);
}
拼音
引入依賴:
<dependency>
<groupId>io.github.biezhi</groupId>
<artifactId>TinyPinyin</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
獲取拼音:
@Test
void testGetPinyin() {
Assertions.assertEquals("ceng", PinyinUtil.getPinyin("曾"));
Assertions.assertEquals("f o o", PinyinUtil.getPinyin("foo"));
Assertions.assertThrowsExactly(NullPointerException.class, () -> PinyinUtil.getPinyin(null));
Assertions.assertEquals(" ", PinyinUtil.getPinyin(" "));
// ? ?
log.info("{}", PinyinUtil.getPinyin("??"));
Assertions.assertEquals("! # ¥ % ( # ) @", PinyinUtil.getPinyin("!#¥%(#)@"));
}
壓縮
轉換
@Test
void testDigitToChinese() {
Assertions.assertEquals("零元零壹分",Convert.digitToChinese(0.01));
}
二維碼
@Test
void testGenerate() {
// 生成二維碼
final BufferedImage image = QrCodeUtil.generate("https://hutool.cn/", 300, 300);
Assertions.assertNotNull(image);
}
SpringUtil
SpringUtil 實作了通過 @EnalbeAutoConfiguuration 自動裝配 Bean,檔案 spring.factories 定義如下:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.hutool.extra.spring.SpringUtil
// 獲取bean
final Demo2 testDemo = SpringUtil.getBean("testDemo");
版本比較
@Test
void testCompare() {
Assertions.assertEquals(-1, VersionComparator.INSTANCE.compare("1.12.1", "1.12.1c"));
Assertions.assertEquals(1, VersionComparator.INSTANCE.compare("V0.0.20170102", "V0.0.20170101"));
}
身份證
private static final String ID_18 = "321083197812162119";
private static final String ID_15 = "150102880730303";
/**
* 根據身份編號獲取生日,只支持15或18位身份證號碼.
*/
@Test
void testGetBirthByIdCard() {
Assertions.assertEquals(IdcardUtil.getBirthByIdCard(ID_18), "19781216");
Assertions.assertEquals(IdcardUtil.getBirthByIdCard(ID_15), "19880730");
}
打碼/資訊脫敏
void testIdCardNum() {
Assertions.assertEquals("5***************1X",
DesensitizedUtil.idCardNum("51343620000320711X", 1, 2));
}
@Test
void testMobilePhone() {
Assertions.assertEquals("180****1999", DesensitizedUtil.mobilePhone("18049531999"));
}
@Test
void testPassword() {
Assertions.assertEquals("**********", DesensitizedUtil.password("1234567890"));
}
@Test
void testEmail() {
Assertions.assertEquals("d********@126.com", DesensitizedUtil.email("[email protected]"));
Assertions.assertEquals("d********@gmail.com.cn", DesensitizedUtil.email("[email protected]"));
Assertions.assertEquals("d*************@gmail.com.cn", DesensitizedUtil.email("[email protected]"));
}
加密
引入依賴:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>1.69</version>
</dependency>
SM4 對稱加密:
String content = "test中文"; SymmetricCrypto sm4 = SmUtil.sm4();
String encryptHex = sm4.encryptHex(content);
String decryptStr = sm4.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8);
JDK
Collections
回傳空陣列:
@Test
void testEmptyList() {
Assertions.assertTrue(Collections.emptyList().isEmpty());
}
Arrays
列印陣列資訊,方便debug:
@Test
void testToString() {
Assertions.assertEquals("[a, b, c]",Arrays.toString(new String[]{"a","b","c"}));
Assertions.assertEquals("null",Arrays.toString((String[]) null));
}
Duration
有時候我們傳遞一些時間引數,單位可能是秒、毫米、分鐘、小時等,例如執行緒睡眠時間,我們可以使用 Duration 來語意化我們的代碼:
@Test
void test() throws InterruptedException {
Thread.currentThread().sleep(Duration.ofSeconds(1).toMillis());
}
StandardCharsets
我們有時候需要用到字符集,例如:
URLEncoderInputStreamReaderIOUtils.toString
可以使用 StandardCharsets,例如:
IOUtils.toString(new ClassPathResource("log4j2.xml").getInputStream(), StandardCharsets.UTF_8)
Objects
物件 equals :
@Test
void testEquals() {
Assertions.assertTrue(Objects.equals(null, null));
Assertions.assertFalse(Objects.equals("a", "b"));
}
避免空指標獲取 hashCode:
@Test
void testHashCode() {
Assertions.assertEquals(0, Objects.hashCode(null));
Assertions.assertEquals("a".hashCode(), Objects.hashCode("a"));
}
null 轉默認值:
@Test
void testRequireNonNullElse() {
Assertions.assertEquals("a", Objects.requireNonNullElse(null, "a"));
}
判斷物件不為空,配合 Stream :
@Test
void testNonNull() {
List<String> names = Lists.newArrayList("foo", null);
names = names.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
Assertions.assertEquals(names, List.of("foo"));
}
Optional
@Test
void testOptional() {
// 創建一個 Optional 物件,不允許為空
Optional<String> optional = Optional.of("a");
// 獲取值,如果值為空拋出 NoSuchElementException 例外
Assertions.assertEquals("a", optional.get());
// 判斷Optional的值是否為空
Assertions.assertFalse(optional.isEmpty());
// 判斷Optional的值是否不為空
Assertions.assertTrue(optional.isPresent());
// 創建一個 Optional 物件,允許為 null
optional = Optional.ofNullable(null);
// 獲取值,如果值為空拋出 NoSuchElementException 例外
Assertions.assertThrowsExactly(NoSuchElementException.class, optional::get);
// 判斷Optional的值是否為空
Assertions.assertTrue(optional.isEmpty());
// 判斷Optional的值是否不為空
Assertions.assertFalse(optional.isPresent());
// 創建一個空的Optional物件
optional = Optional.empty();
// 獲取值,如果值為空拋出 NoSuchElementException 例外
Assertions.assertThrowsExactly(NoSuchElementException.class, optional::get);
// 判斷Optional的值是否為空
Assertions.assertTrue(optional.isEmpty());
// 判斷Optional的值是否不為空
Assertions.assertFalse(optional.isPresent());
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/538452.html
標籤:其他
上一篇:day24-服務器端渲染技術02
下一篇:<一>繼承的基本意義
