隆重向你推薦這 8 個(gè)開源 Java 類庫

昨天在青銅時(shí)代群里看到讀者朋友們在討論 Java 最常用的工具類,我覺得大家推薦的確實(shí)都挺常見的,我自己用的頻率也蠻高的。恰好我在 programcreek 上看到過一篇類似的文章,就想著梳理一下分享給大家。

在 Java 中,工具類通常用來定義一組執(zhí)行通用操作的方法。本篇文章將會向大家展示 8 個(gè)工具類以及它們最常用的方法,類的排名和方法的排名均來自可靠的數(shù)據(jù),從 GitHub 上最受歡迎的 50000 個(gè)開源 Java 項(xiàng)目中精心挑選。

為了方便大家的理解,我會在介紹每個(gè)類的方法時(shí)寫一段小 Demo,這樣大家就能知道每個(gè)方法該怎么用。放心吧,方法是干嘛的我也不會保密的。??

1)IOUtils

org.apache.commons.io.IOUtils,操作 IO 流的工具類,下面是其常用的方法。

  • closeQuietly(),關(guān)閉 IO 流,并且忽略 null 值和異常。
IOUtils.closeQuietly(output);
  • copy(),將字節(jié)從輸入流復(fù)制到輸出流。
IOUtils.copy(inputStream, new FileOutputStream(File));
  • toByteArray(),以 byte[] 的形式獲取輸入流中的內(nèi)容。
URLConnection conn = new URL(url).openConnection();
InputStream is = conn.getInputStream();
byte[] result = IOUtils.toByteArray(is);
  • write(),將字符或者字節(jié)寫入輸出流中。
IOUtils.write("沉默王二", response.getOutputStream(), "UTF-8");
  • toInputStream(),將指定的字符轉(zhuǎn)成輸入流。
String content=req.getParameter("content");
InputStream inputStream=IOUtils.toInputStream(content,"utf-8");
  • readLines(),從輸入流中一行一行地讀取,并按照指定的字符編碼返回字符串列表。
List<String> lines = IOUtils.readLines(new InputStreamReader(new FileInputStream(file), "utf-8"));
  • copyLarge(),從輸入流中復(fù)制內(nèi)容到輸出流,超過 2GB。
private File downloadFile(HttpResponse response) {
    File dir = new File("downloadedFiles");
    if (!dir.exists()) {
        dir.mkdir();
    }
    File outputFile = new File("downloadedFiles/temp" + RandomStringUtils.randomAlphanumeric(3));
    try {
        IOUtils.copyLarge(response.getEntity().getContent(), new FileOutputStream(outputFile));
        return outputFile;
    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {
        request.releaseConnection();
    }
}
  • readFully(),把輸入流中的內(nèi)容讀入到字節(jié)數(shù)組中。
byte[] intArray = new byte[Bytes.SIZEOF_INT];
IOUtils.readFully(in, intArray);

2)FileUtils

org.apache.commons.io.FileUtils,操作文件或者目錄的工具類,下面是其常用的方法。

  • deleteDirectory(),刪除目錄。
FileUtils.deleteDirectory(file);
  • readFileToString(),把文件的內(nèi)容讀入到字符串中。
String fileAsString = FileUtils.readFileToString(reportFile);
  • deleteQuietly(),刪除文件,但不拋出異常。
 FileUtils.deleteQuietly(outputFile);
  • copyFile(),把文件復(fù)制到一個(gè)新的位置。
FileUtils.copyFile(source, dest);
  • writeStringToFile(),把字符串寫入到文件。
FileUtils.writeStringToFile(templateFile, generatedText, Charset.forName("UTF-8"));
  • forceMkdir(),強(qiáng)制創(chuàng)建目錄,包括任何必需但不存在的父目錄。
File uploadDirectory = new File(this.uploadPath);
if (!uploadDirectory.exists()) {
    FileUtils.forceMkdir(uploadDirectory);
}
  • write(),把字符或者字節(jié)寫入到文件。
FileUtils.write(new File("C:\\Users\\cmower\\test.txt"), "沉默王二", "utf-8");
  • listFiles(),列出指定目錄下的所有文件。
public void processResultsDirectory(String dirName) {
    File root = new File(dirName);
    try {
        Collection<File> files = FileUtils.listFiles(root,
                new RegexFileFilter(jmeterJTLFileName),
                DirectoryFileFilter.DIRECTORY);

        for (Iterator<File> iterator = files.iterator(); iterator.hasNext();) {
            File file = (File) iterator.next();
            parse(file);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  • copyDirectory(),將目錄下的所有子目錄及文件復(fù)制到新的目錄。
 FileUtils.copyDirectory(source, dest);
  • forceDelete(),強(qiáng)制刪除文件或者目錄及其所有子目錄和文件。
 FileUtils.forceDelete(tmpFile);

3)StringUtils

org.apache.commons.lang3.StringUtils,操作字符串的工具類,并且是 null 安全的,下面是其常用的方法。

  • isBlank(),檢查字符是否為空字符串"",或者 null,或者空格。
if (StringUtils.isBlank(name))
{
throw new IllegalArgumentException("姓名不能為空");
}

檢查結(jié)果如下所示。

StringUtils.isBlank(null)      = true
StringUtils.isBlank("")        = true
StringUtils.isBlank(" ")       = true
StringUtils.isBlank("沉默王二")     = false
StringUtils.isBlank("  沉默王二  ") = false
  • isNotBlank(),與 isBlank() 檢查的結(jié)果相反。

  • isEmpty(),檢查字符是否為空字符串"",或者 null;和 isBlank() 不同,不包括空格的檢查。

if (StringUtils.isEmpty(name)) {
    throw new IllegalArgumentException("姓名不能為 null 或者空字符串");
}

檢查結(jié)果如下所示。

StringUtils.isEmpty(null)      = true
StringUtils.isEmpty("")        = true
StringUtils.isEmpty(" ")       = false
StringUtils.isEmpty("沉默王二")     = false
StringUtils.isEmpty("  沉默王二  ") = false
  • isNotEmpty(),與 isEmpty() 檢查的結(jié)果相反。
  • join(),將多個(gè)元素連接成一個(gè)字符串。
StringUtils.join(null)            = null
StringUtils.join([])              = ""
StringUtils.join([null])          = ""
StringUtils.join(["沉默", "王二"]) = "沉默王二"
StringUtils.join([null, "", "一枚有趣的程序員"]) = "一枚有趣的程序員"
  • equals(),比較兩個(gè)字符序列是否相等。
StringUtils.equals(null, null)   = true
StringUtils.equals(null, "沉默王二")  = false
StringUtils.equals("沉默王二", null)  = false
StringUtils.equals("沉默王二", "沉默王二") = true
StringUtils.equals("cmower", "CMOWER") = false
  • split(),把字符串拆分為數(shù)組,拆分符為空白字符。
 StringUtils.split(null)       = null
 StringUtils.split("")         = []
 StringUtils.split("沉默王二 沉默王三")  = ["沉默王二", "沉默王三"]
 StringUtils.split("沉默王二  沉默王三") = ["沉默王二", "沉默王三"]
 StringUtils.split(" 沉默王二 ")    = ["沉默王二"]
  • replace(),替換另一個(gè)字符串中所有出現(xiàn)的字符串。
StringUtils.replace(null, *, *)        = null
StringUtils.replace("", *, *)          = ""
StringUtils.replace("any", null, *)    = "any"
StringUtils.replace("any", *, null)    = "any"
StringUtils.replace("any", "", *)      = "any"
StringUtils.replace("沉默王二", "二", null)  = "沉默王二"
StringUtils.replace("沉默王二", "二", "")    = "沉默王"
StringUtils.replace("沉默王二", "二", "三")   = "沉默王三"

4)FilenameUtils

org.apache.commons.io.FilenameUtils,操作文件名或者路徑的工具類,下面是其常用的方法。

  • getExtension(),獲取文件的擴(kuò)展名。
FilenameUtils.getExtension("牛逼.txt");        --> "txt"
FilenameUtils.getExtension("a/b/牛逼.jpg");    --> "jpg"
FilenameUtils.getExtension("a/牛逼.txt/c");    --> ""
FilenameUtils.getExtension("a/b/c");           --> ""
  • getBaseName(),獲取單純的文件名或者路徑名,文件時(shí)去掉路徑和擴(kuò)展名;路徑時(shí)去掉父級路徑。
FilenameUtils.getBaseName("a/b/牛逼.txt");        --> "牛逼"
FilenameUtils.getBaseName("牛逼.txt");            --> "牛逼"
FilenameUtils.getBaseName("a/b/c");               --> c
FilenameUtils.getBaseName("a/b/c/");              --> ""
  • getName(),如果是文件時(shí),獲取文件名和后綴,去掉路徑;如果是路徑時(shí),去掉父級路徑。
FilenameUtils.getName("a/b/牛逼.txt");        --> "牛逼.txt"
FilenameUtils.getName("牛逼.txt");            --> "牛逼.txt"
FilenameUtils.getName("a/b/c");               --> c
FilenameUtils.getName("a/b/c/");              --> ""
  • concat(),將路徑和文件名連接在一起。
FilenameUtils.concat("/foo/", "bar");          -->   /foo/bar
FilenameUtils.concat("/foo", "bar");           -->   /foo/bar
FilenameUtils.concat("/foo", "/bar");          -->   /bar
FilenameUtils.concat("/foo", "C:/bar");        -->   C:/bar
FilenameUtils.concat("/foo", "C:bar");         -->   C:bar (*)
FilenameUtils.concat("/foo/a/", "../bar");     -->   foo/bar
FilenameUtils.concat("/foo/", " ../../bar");    -->   null
FilenameUtils.concat("/foo/", "/bar");        -->   /bar
FilenameUtils.concat("/foo/.. ", "/bar");       -->   /bar
FilenameUtils.concat("/foo", " bar/c.txt");     -->   /foo/bar/c.txt
FilenameUtils.concat("/foo/c.txt", "bar");     -->   /foo/c.txt/bar (!)
  • wildcardMatch(),檢查文件名是否匹配指定的格式。
wildcardMatch("c.txt", "*.txt")      --> true
wildcardMatch("c.txt", "*.jpg")      --> false
wildcardMatch("a/b/c.txt", "a/b/*")  --> true
wildcardMatch("c.txt", "*.???")      --> true
wildcardMatch("c.txt", "*.????")     --> false
  • separatorsToUnix(),將所有分隔符轉(zhuǎn)換為正斜杠的 Unix 分隔符。
FilenameUtils.separatorsToUnix("my/unix/filename");
  • getFullPath(),獲取文件的完整路徑。
getFullPath("C:\a\b\c.txt" --> C:\a\b\
getFullPath("~/a/b/c.txt"  --> ~/a/b/
getFullPath("a.txt"        --> ""

5)ArrayUtils

org.apache.commons.lang3.ArrayUtils,操作數(shù)組的工具類,下面是其常用的方法。

  • contains(),檢查數(shù)組中是否包含某個(gè)值
public static boolean containsAll(Object[] one, Object[] two) {
    for (Object b : two) {
        if (!ArrayUtils.contains(one, b)) {
            return false;
        }
    }
    return true;
}
  • addAll(),將所有元素添加到一個(gè)數(shù)組中。
ArrayUtils.addAll(null, null)     = null
ArrayUtils.addAll(array1, null)   = cloned copy of array1
ArrayUtils.addAll(null, array2)   = cloned copy of array2
ArrayUtils.addAll([], [])         = []
ArrayUtils.addAll([null], [null]) = [null, null]
ArrayUtils.addAll(["a", "b", "c"], ["1", "2", "3"]) = ["a", "b", "c", "1", "2", "3"]
  • clone(),淺拷貝一個(gè)數(shù)組。
public QualityGateTask[] getQueue() {
    return (QualityGateTask[]) ArrayUtils.clone(queue);
}
  • isEmpty(),檢查數(shù)組是否為 null 或者沒有元素。
if (ArrayUtils.isEmpty(objectIds)) {
    throw new IllegalArgumentException("對象的ID不能為空");
}
  • add(),在數(shù)組中添加一個(gè)新的元素,原數(shù)組不變。
ArrayUtils.add(null, true)          = [true]
ArrayUtils.add([true], false)       = [true, false]
ArrayUtils.add([true, false], true) = [true, false, true]
  • subarray(),根據(jù)起始下標(biāo)和結(jié)束下標(biāo)截取一個(gè)子數(shù)組。
public byte[] fetchData(String blobKey, long startIndex, long l) {
  CountingInputStream inputStream = new CountingInputStream(getInputStream(blobKey));
  byte[] bytes = new byte[(int) l];
  try {
    int readSize = inputStream.read(bytes, (int) startIndex, (int) l);
    if (readSize < l) {
      bytes = ArrayUtils.subarray(bytes, 0, readSize - 1);
    }
  } catch (IOException e) {
    LOGGER.warn("Failed to read bytes", e);
  } finally {
    try {
      inputStream.close();
    } catch (IOException ignored) {
      LOGGER.warn("Exception while closing inputStream", ignored);
    }
  }
  return bytes;
}
  • indexOf(),找出指定數(shù)組的下標(biāo)。
ArrayUtils.indexOf(idxVal, i);

6)DigestUtils

org.apache.commons.codec.digest.DigestUtils,加密的工具類,下面是其常用的方法。

  • md5Hex(),計(jì)算字符串的 MD5 摘要,并返回 32 位的十六進(jìn)制字符。
DigestUtils.md5Hex("沉默王二");
  • md5(),計(jì)算字符串的 MD5 摘要,并返回 16 個(gè)元素的字節(jié)數(shù)組。
DigestUtils.md5("沉默王二");

7)StringEscapeUtils

org.apache.commons.text.StringEscapeUtils,字符串的轉(zhuǎn)義和反轉(zhuǎn)義工具類,下面是其常用的方法。

  • unescapeHtml4(),反轉(zhuǎn)義 HTML。
StringEscapeUtils.unescapeHtml4("&lt;div&gt;&lt;/div&gt;");-->   <div></div>
  • escapeHtml4(),轉(zhuǎn)義 HTML。
StringEscapeUtils.escapeHtml4("<div></div>");-->   &lt;div&gt;&lt;/div&gt;
  • escapeJava(),轉(zhuǎn)義 Java。
StringEscapeUtils.escapeJava("沉默王二");-->   \u6C89\u9ED8\u738B\u4E8C
  • unescapeJava()
StringEscapeUtils.escapeJava("\u6C89\u9ED8\u738B\u4E8C");-->   沉默王二

8)BeanUtils

大多數(shù) Java 開發(fā)人員習(xí)慣于創(chuàng)建 getter/setter 的JavaBean,然后通過調(diào)用相應(yīng)的 getXxxsetXxx 方法訪問對應(yīng)字段。但在某些情況下,需要動態(tài)訪問 Java 對象的屬性,org.apache.commons.beanutils.BeanUtils 就派上用場了。

  • copyProperties(),拷貝所有屬性。
private static void dto2Entity() {
    UserDTO user = new UserDTO();
    user.setId(1l);
    user.setUsername("joking");
    user.setCreationDate("2016-04-20");
    
    EUser u = new EUser();
    ConvertUtils.register(new DateStringConverter(), Date.class);
    try {
        BeanUtils.copyProperties(u, user);
    } catch (IllegalAccessException | InvocationTargetException e) {
        e.printStackTrace();
    }
}

其中 UserDTO 類的源碼如下所示。

public class UserDTO implements Serializable {
    
    private static final long serialVersionUID = 2963408818099106614L;

    private long id;

    private String username;

    private String creationDate;

    // getter/setter

    @Override
    public String toString() {
        return "UserDTO [id=" + id + ", username=" + username + ", creationDate=" + creationDate + "]";
    }

}

其中 EUser 類的源碼如下所示。

public class EUser implements Serializable {
    private static final long serialVersionUID = -692192937932555368L;

    private long id;

    private String username;

    private Date creationDate;

    //getter/setter

    @Override
    public String toString() {
        return "EUser [id=" + id + ", username=" + username + ", creationDate=" + creationDate + "]";
    }

}

其中 DateStringConverter 類的源碼如下所示。

public class DateStringConverter implements Converter {

    @SuppressWarnings("unchecked")
    @Override
    public <T> T convert(Class<T> type, Object value) {
        if(type.equals(Date.class) && String.class.isInstance(value)) {
            return (T)DateUtils.convert((String)value);
        } else if(type.equals(String.class) && Date.class.isInstance(value)){
            return (T)DateUtils.format((Date)value);
        } else {
            return (T)value;
        }
    }

}
  • getProperty(),返回 bean 指定的屬性值。
String fieldValue = BeanUtils.getProperty(value, fieldName);
  • setProperty(),設(shè)置 bean 指定的屬性值。
BeanUtils.setProperty(object, propertyName, value);

說實(shí)在的,沒想到整理起來這么費(fèi)事,不知不覺 5 個(gè)小時(shí)過去了。每個(gè)類都有很多方法,還要為每個(gè)方法敲一個(gè) Demo,真的是很辛苦。但為了你們,再苦再累二哥也心甘情愿啊。

雖然是技術(shù)文,但我想大家應(yīng)該仍然能感受到我的文風(fēng)比較幽默風(fēng)趣。上次和純潔的微笑、江南一點(diǎn)雨他們在南京小聚的時(shí)候,他們也感慨說:“之前一直未曾謀面,這次一見,二哥真心文如其人啊,騷氣?!边@話真不是貶義詞,這年頭,生活壓力這么大,像我這樣能夠?qū)ι畋3謽酚^的人不多了,希望你們在閱讀我的文章時(shí)也能夠感受到快樂,我是認(rèn)真的!

原創(chuàng)不易,如果覺得有點(diǎn)用的話,請不要吝嗇你手中點(diǎn)贊的權(quán)力;如果想要第一時(shí)間看到二哥更新的文章,請掃描下方的二維碼,關(guān)注沉默王二公眾號。我們下篇文章見!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容