Java 8 API 示例:字符串、数值、算术和文件

译者:飞龙

大量的教程和文章都涉及到Java8中最重要的改变,例如lambda表达式和函数式数据流。但是此外许多现存的类在JDK 8 API中也有所改进,带有一些实用的特性和方法。

这篇教程涉及到Java 8 API中的那些小修改 -- 每个都使用简单易懂的代码示例来描述。让我们好好看一看字符串、数值、算术和文件。

处理字符串

两个新的方法可在字符串类上使用:join和chars。第一个方法使用指定的分隔符,将任何数量的字符串连接为一个字符串。

String.join(":", "foobar", "foo", "bar");

// => foobar:foo:bar

第二个方法chars从字符串所有字符创建数据流,所以你可以在这些字符上使用流式操作。

"foobar:foo:bar"

.chars()

.distinct()

.mapToObj(c -> String.valueOf((char)c))

.sorted()

.collect(Collectors.joining());

// => :abfor

不仅仅是字符串,正则表达式模式串也能受益于数据流。我们可以分割任何模式串,并创建数据流来处理它们,而不是将字符串分割为单个字符的数据流,像下面这样:

Pattern.compile(":")

.splitAsStream("foobar:foo:bar")

.filter(s -> s.contains("bar"))

.sorted()

.collect(Collectors.joining(":"));

// => bar:foobar

此外,正则模式串可以转换为谓词。这些谓词可以像下面那样用于过滤字符串流:

Pattern pattern = Pattern.compile(".*@gmail\\.com");

Stream.of("bob@gmail.com", "alice@hotmail.com")

.filter(pattern.asPredicate())

.count();

// => 1

上面的模式串接受任何以@gmail.com结尾的字符串,并且之后用作Java8的Predicate来过滤电子邮件地址流。

处理数值

Java8添加了对无符号数的额外支持。Java中的数值总是有符号的,例如,让我们来观察Integer:

int可表示最多2 ** 32个数。Java中的数值默认为有符号的,所以最后一个二进制数字表示符号(0为正数,1为负数)。所以从十进制的0开始,最大的有符号正整数为2 ** 31 - 1。

你可以通过Integer.MAX_VALUE来访问它:

System.out.println(Integer.MAX_VALUE); // 2147483647

System.out.println(Integer.MAX_VALUE + 1); // -2147483648

Java8添加了解析无符号整数的支持,让我们看看它如何工作:

long maxUnsignedInt = (1l << 32) - 1;

String string = String.valueOf(maxUnsignedInt);

int unsignedInt = Integer.parseUnsignedInt(string, 10);

String string2 = Integer.toUnsignedString(unsignedInt, 10);

就像你看到的那样,现在可以将最大的无符号数2 ** 32 - 1解析为整数。而且你也可以将这个数值转换回无符号数的字符串表示。

这在之前不可能使用parseInt完成,就像这个例子展示的那样:

try {

Integer.parseInt(string, 10);

}

catch (NumberFormatException e) {

System.err.println("could not parse signed int of " + maxUnsignedInt);

}

这个数值不可解析为有符号整数,因为它超出了最大范围2 ** 31 - 1。

算术运算

Math工具类新增了一些方法来处理数值溢出。这是什么意思呢?我们已经看到了所有数值类型都有最大值。所以当算术运算的结果不能被它的大小装下时,会发生什么呢?

System.out.println(Integer.MAX_VALUE); // 2147483647

System.out.println(Integer.MAX_VALUE + 1); // -2147483648

就像你看到的那样,发生了整数溢出,这通常是我们不愿意看到的。

Java8添加了严格数学运算的支持来解决这个问题。Math扩展了一些方法,它们全部以exact结尾,例如addExact。当运算结果不能被数值类型装下时,这些方法通过抛出ArithmeticException异常来合理地处理溢出。

try {

Math.addExact(Integer.MAX_VALUE, 1);

}

catch (ArithmeticException e) {

System.err.println(e.getMessage());

// => integer overflow

}

当尝试通过toIntExact将长整数转换为整数时,可能会抛出同样的异常:

try {

Math.toIntExact(Long.MAX_VALUE);

}

catch (ArithmeticException e) {

System.err.println(e.getMessage());

// => integer overflow

}

处理文件

Files工具类首次在Java7中引入,作为NIO的一部分。JDK8 API添加了一些额外的方法,它们可以将文件用于函数式数据流。让我们深入探索一些代码示例。

列出文件

Files.list方法将指定目录的所有路径转换为数据流,便于我们在文件系统的内容上使用类似filter和sorted的流操作。

try (Stream stream = Files.list(Paths.get(""))) {

String joined = stream

.map(String::valueOf)

.filter(path -> !path.startsWith("."))

.sorted()

.collect(Collectors.joining("; "));

System.out.println("List: " + joined);

}

上面的例子列出了当前工作目录的所有文件,之后将每个路径都映射为它的字符串表示。之后结果被过滤、排序,最后连接为一个字符串。如果你还不熟悉函数式数据流,你应该阅读我的Java8数据流教程。

你可能已经注意到,数据流的创建包装在try-with语句中。数据流实现了AutoCloseable,并且这里我们需要显式关闭数据流,因为它基于IO操作。

返回的数据流是DirectoryStream的封装。如果需要及时处理文件资源,就应该使用try-with结构来确保在流式操作完成后,数据流的close方法被调用。

查找文件

下面的例子演示了如何查找在目录及其子目录下的文件:

Path start = Paths.get("");

int maxDepth = 5;

try (Stream stream = Files.find(start, maxDepth, (path, attr) ->

String.valueOf(path).endsWith(".js"))) {

String joined = stream

.sorted()

.map(String::valueOf)

.collect(Collectors.joining("; "));

System.out.println("Found: " + joined);

}

find方法接受三个参数:目录路径start是起始点,maxDepth定义了最大搜索深度。第三个参数是一个匹配谓词,定义了搜索的逻辑。上面的例子中,我们搜索了所有JavaScirpt文件(以.js结尾的文件名)。

我们可以使用Files.walk方法来完成相同的行为。这个方法会遍历每个文件,而不需要传递搜索谓词。

Path start = Paths.get("");

int maxDepth = 5;

try (Stream stream = Files.walk(start, maxDepth)) {

String joined = stream

.map(String::valueOf)

.filter(path -> path.endsWith(".js"))

.sorted()

.collect(Collectors.joining("; "));

System.out.println("walk(): " + joined);

}

这个例子中,我们使用了流式操作filter来完成和上个例子相同的行为。

读写文件

将文本文件读到内存,以及向文本文件写入字符串在Java 8 中是简单的任务。不需要再去摆弄读写器了。Files.readAllLines从指定的文件把所有行读进字符串列表中。你可以简单地修改这个列表,并且将它通过Files.write写到另一个文件中:

List lines = Files.readAllLines(Paths.get("res/nashorn1.js"));

lines.add("print('foobar');");

Files.write(Paths.get("res/nashorn1-modified.js"), lines);

要注意这些方法对内存并不十分高效,因为整个文件都会读进内存。文件越大,所用的堆区也就越大。

你可以使用Files.lines方法来作为内存高效的替代。这个方法读取每一行,并使用函数式数据流来对其流式处理,而不是一次性把所有行都读进内存。

try (Stream stream = Files.lines(Paths.get("res/nashorn1.js"))) {

stream

.filter(line -> line.contains("print"))

.map(String::trim)

.forEach(System.out::println);

}

如果你需要更多的精细控制,你需要构造一个新的BufferedReader来代替:

Path path = Paths.get("res/nashorn1.js");

try (BufferedReader reader = Files.newBufferedReader(path)) {

System.out.println(reader.readLine());

}

或者,你需要写入文件时,简单地构造一个BufferedWriter来代替:

Path path = Paths.get("res/output.js");

try (BufferedWriter writer = Files.newBufferedWriter(path)) {

writer.write("print('Hello World');");

}

BufferedReader也可以访问函数式数据流。lines方法在它所有行上面构建数据流:

Path path = Paths.get("res/nashorn1.js");

try (BufferedReader reader = Files.newBufferedReader(path)) {

long countPrints = reader

.lines()

.filter(line -> line.contains("print"))

.count();

System.out.println(countPrints);

}

目前为止你可以看到Java8提供了三个简单的方法来读取文本文件的每一行,使文件处理更加便捷。

不幸的是你需要显式使用try-with语句来关闭文件流,这会使示例代码有些凌乱。我期待函数式数据流可以在调用类似count和collect时可以自动关闭,因为你不能在相同数据流上调用终止操作两次。

我希望你能喜欢这篇文章。所有示例代码都托管在Github上,还有来源于我博客其它Java8文章的大量的代码片段。如果这篇文章对你有所帮助,请收藏我的仓库,并且在Twitter上关注我。

请坚持编程!

java编写api取数据_Java 8 API 示例:字符串、数值、算术和文件相关推荐

  1. java set中取数据_Java中取数据库用的ResultSet问题

    这段时间做java项目,在操作数据库的时候,犯了一个错误,请看下面的程序 .......                        //前面连接数据库方面的省略 ResultSet  result ...

  2. java前端ajax提交数据_Java 前端使用Ajax通过FormData传递文件和表单数据到后台

    提交 1,当仅仅想上传文件到后台 function tijiao(){ var file = $("#image")[0].files[0]; //打印file 为对象 conso ...

  3. Java编写程序将数据存入Kafka中

    Kafka是一个类似于RabbitMQ的消息系统,它的主要功能是消息的发布和订阅.处理和存储. 1.它类似于一个消息系统,读写流式的数据. 2.编写可扩展的流应用处理程序,用于实时事件响应的场景. 3 ...

  4. java中api是什么_java中API总结

    1.什么是API? 可以理解为Java自己提供的标准类库,开发人员可直接使用其方法, 而不用进行源码实现.如常用的打印方法:System.out.println();,这是Java自己提供的东西. 官 ...

  5. java 爬取数据_JAVA爬取天天基金网数据

    爬取基金历史记录代码: 1.首先要自己定义几个参数:基金编码,页数,每页显示条数 开始时间结束时间等 (我这直接写的静态方法使用的 大家可以改成Test方法自行进行测试) /*** httClient ...

  6. java object取数据_java使用ObjectInputStream从文件中读取对象

    import java.io.EOFException; import java.io.FileInputStream; import java.io.FileNotFoundException; i ...

  7. java中的取模_Java 中的取模和取余

    期末复习密码学时需要用到取模运算,发现 Java 中的 % 运算符并不是取模运算(Modulo Operation),而是取余运算(Complementation). 计算方法 对于整数 a,b 来说 ...

  8. java获取前端json数据_java如何获取前端ajax传来的json对象

    假设使用 jQuery 中的 ajax 1. Json 对象 前端代码示例 $.ajax({ url : 'http://localhost:8888/demo', type: 'post', dat ...

  9. java解析ajax的数据_java ajax 请求后获取 json 数据 以及 使用 解析 ,解惑

    写这个内容是 因为...框架一直在用ajax ,,传输 json 但是一直不太明白为什么要这样配置, 以及 前端ajax 怎么 使用 后台传输过来的数据. 首先 是 spirng mvc 的 配置 c ...

  10. java 对第三方的异常_Java第三方API调用打开文件方法时抛出异常

    想用Java写一个音乐播放器,使用了Javazoom里的第三方API,调用打开文件的方法open(File file)时,抛出了IOException:Resetting to invalid mar ...

最新文章

  1. java编写词法分析器
  2. Java编程中写出好代码的建议
  3. 卫星导航技术的源起很有戏剧性
  4. Python中的sort()方法使用基础
  5. php在数据流(内存)中操纵远程数据
  6. [react] 在React中如何判断点击元素属于哪一个组件?
  7. 宝塔面板搭建autoPicCdn:一款基于jsdelivr-Github的免费CDN图床
  8. Jquery Highcharts 参数配置说明
  9. NLP简报(Issue #3)
  10. 【PAT乙】1080 MOOC期终成绩 (25分)
  11. java安装包的大概组成部分
  12. 一文整理总结常见Java后端面试题系列——Spring篇(2022最新版)
  13. 第四百九十一章 战利品
  14. Exp6 信息搜集与漏洞扫描 ——20164316张子遥
  15. unity (初学者的个人问题)
  16. iphone 日历 灰色_将iPhone假期日历更改为本地日历
  17. C3P0 连接池时报 TimeoutException 的解决方法
  18. Udacity优达学城 TensorFlow笔记2-对服饰图像分类
  19. MoveIt 概念、安装、学习教程
  20. Android脚本软件,免费脚本软件安卓化

热门文章

  1. 【人脸识别】基于matlab GUI形态学教室人数统计(带面板)【含Matlab源码 1703期】
  2. 【元胞自动机】基于matlab激进策略元胞自动机三车道(不开放辅路,软件园影响)交通流模型【含Matlab源码 1297期】
  3. 【脑电信号】基于matlab小波变换睡眠脑电信号监测【含Matlab源码 595期】
  4. 【花朵识别】基于matlab模板匹配花朵分类【含Matlab源码 472期】
  5. 【图像分割】基于matlab分水岭算法图像分割【含Matlab源码 390期】
  6. 【数据分析】基于matlab GUI成绩管理系统【含Matlab源码 256期】
  7. db2和oracle数据同步,DB2与Oracle数据库之间的远程复制(转)
  8. knx智能照明控制系统电路图_智能照明控制系统(KNX)讲解
  9. 【C++】set和multiset区别
  10. we8iso8859p1 java_字符集WE8ISO8859P1 是不能改为ZHS16GBK的