Java 11没有引入任何创新功能,但是它包含了一些您可能还没有听说过的瑰宝。 已经查看过String
, Optional
, Collection
和其他主要功能中的最新功能? 如果没有,那么您来了:今天,我们将看一下Java 11中的11个隐藏的宝石!
Lambda参数的类型推断
在编写lambda表达式时,可以在显式指定类型和跳过它们之间进行选择:
Function<String, String> append = string -> string + " "; Function<String, String> append = (String s) -> s + " ";
Java 10引入了 var
,但是不能在lambdas中使用:
在Java 11中已经可以实现。 但是为什么呢? 看起来var
提供的不仅仅是类型传递。 尽管是这种情况,但使用var
有两个次要优点:
- 通过删除规则的异常,使使用
var
更通用 - 允许您向参数类型添加注释,而无需使用其全名
这是第二种情况的示例:
List<EnterpriseGradeType<With, Generics>> types = ; types .stream()
尽管可以在形式为(var type, String option, index) -> ...
lambda表达式中混合派生的显式和隐式类型,但是( 在JEP-323框架中 )这项工作没有执行。 因此,有必要选择三种方法之一,并对lambda表达式的所有参数都坚持使用。 需要为所有参数指定var
以便为其中一个参数添加注释可能会有些烦人,但通常是可以忍受的。
使用'String::lines'
对字符串进行流处理
有多行字符串? 想要对每一行做点什么? 那么String::lines
是正确的选择:
var multiline = "\r\n\r\n\r\n"; multiline .lines()
请注意,原始行使用\r\n
螺丝定界符,尽管我在Linux上,但lines()
仍然将其破坏。 这是由于以下事实:尽管使用了当前的操作系统,该方法仍将\r
, \n
和\r\n
为换行符-即使它们混在同一行中。
行流永远不会包含行分隔符本身。 行可以为空( "\n\n \n\n"
,其中包含5行),但是如果原始行的最后一行为空,则忽略该行( "\n\n"
; "\n\n"
; 2行)。 (译者注:他们有line
,但是有string
,我们都很方便。)
不同于split("\R")
,各lines()
惰性的, 我引用 “通过更快地搜索新的换行符来提供更好的性能”。 (如果有人想在JMH上发布基准进行验证,请告诉我)。 它还可以更好地反映处理算法,并使用更方便的数据结构(流而不是数组)。
用'String::strip'
等删除空格
最初, String
有一个trim
方法来删除空格,这被认为是所有代码不超过U+0020
。 是的, BACKSPACE
( U+0008)
是一个类似于BELL
( U+0007
)的空白,但是不再将LINE SEPARATOR
( U+2028
)视为空格。
Java 11引入了strip
方法,该方法具有更多细微差别。 它使用Java 5中的Character::isWhitespace
来确定确切需要删除的内容。 从其文档中可以明显看出:
SPACE SEPARATOR
, LINE SEPARATOR
,参数PARAGRAPH SEPARATOR
,但不是不可分割的空间HORIZONTAL TABULATION
( U+0009
), U+000A
LINE FEED
( U+000A
), VERTICAL TABULATION
( U+000B
), FORM FEED
( U+000C
), CARRIAGE RETURN
( U+000D
)FILE SEPARATOR
U+001E
( U+001C
), GROUP SEPARATOR
U+001E
( U+001D
), RECORD SEPARATOR
U+001E
( U+001E
), UNIT SEPARATOR
U+001E
( U+001F
)
按照相同的逻辑,还有另外两种清洁方法, stripLeading
和stripTailing
,它们完全可以完成对它们的期望。
最后,如果您只需要找出删除空格后该行是否为空,则无需真正删除它们-只需使用isBlank
:
" ".isBlank();
用'String::repeat'
重复字符串
抓住主意:
步骤1:监视JDK

步骤2:查找与StackOverflow相关的问题

步骤3:根据未来的变化得出新的答案

步骤4:????
步骤4:获利

可以想象, String
有一个新的repeat(int)
方法。 它的工作完全符合期望,因此几乎没有讨论。
使用'Path::of'
创建路径
我真的很喜欢Path
API,但是在不同视图之间转换路径(例如Path
, File
, URL
, URI
和String
)仍然很烦人。 通过将两个Paths::get
方法复制Paths::get
方法的Path::of
这一点在Java 11中变得不再那么混乱了:
Path tmp = Path.of("/home/nipa", "tmp"); Path codefx = Path.of(URI.create("http://codefx.org"));
它们可以被认为是规范的,因为两个旧的Paths::get
方法都使用新选项。
使用'Files::readString'
和'Files::writeString'
读写文件
如果需要读取大文件,通常会使用Files::lines
来获取其行的惰性流。 类似地,要写入可能无法完全存储在内存中的大量数据,我使用Files::write
作为Iterable<String>
传递它们。
但是,当我想将文件内容作为一行处理时,这种简单情况又如何呢? 这不是很方便,因为Files::readAllBytes
和Files::write
的相应变体在字节数组上运行。
然后出现Java 11,将readString
和writeString
添加到Files
:
String haiku = Files.readString(Path.of("haiku.txt")); String modified = modify(haiku); Files.writeString(Path.of("haiku-mod.txt"), modified);
清晰易用。 如有必要,可以将Charset
传递给readString
,在writeString
还OpenOptions
一个OpenOptions
数组。
使用'Reader::nullReader'
等来清空I / O。
需要一个不会在任何地方写的OutputStream
吗? 还是一个空的InputStream
? 什么都不做的Reader
和Writer
呢? Java 11拥有全部:
InputStream input = InputStream.nullInputStream(); OutputStream output = OutputStream.nullOutputStream(); Reader reader = Reader.nullReader(); Writer writer = Writer.nullWriter();
(译者注:在commons-io
这些类自2014年左右就已经存在。)
但是,我很惊讶null
真的是最好的前缀吗? 我不喜欢用它来表示“故意缺席”……也许最好使用noOp
? (译者注:由于/dev/null
的常用用法,因此很可能选择了此前缀。)
{ } ~> [ ]
与'Collection::toArray'
如何将集合转换为数组?
第一个选项objects
会丢失有关类型的所有信息,因此它正在运行中。 其余的呢? 两者都很笨重,但第一个较短。 后者创建了所需大小的数组,因此看起来效率更高(也就是说,“似乎效率更高”,请参见信誉 )。 但这真的更有生产力吗? 不,相反,它 (现在) 比较慢 。
但是我为什么要在乎呢? 有没有更好的方法可以做到这一点? 在Java 11中有:
String[] strings_fun = list.toArray(String[]::new);
Collection::toArray
了Collection::toArray
新变体,它接受IntFunction<T[]>
,即 接收数组大小并返回所需大小的数组的函数。 它可以简短地表示为对T[]::new
形式的构造函数的引用(对于著名的T
)。
有趣的是, Collection#toArray(IntFunction<T[]>)
的默认实现始终将0
传递给数组生成器。 最初,我认为此解决方案基于零长度数组的最佳性能,但现在我认为原因可能是对于某些集合而言,计算大小可能是一项非常昂贵的操作,并且您不应该在Collection
的默认实现中使用此方法。 但是,特定的集合实现(例如ArrayList
)可以更改此方法,但是在Java 11中不会更改。 我猜这不值得。
使用'Optional::isEmpty'
缺席检查
随着Optional
的大量使用,尤其是在大型项目中,您经常会遇到非Optional
方法,因此您通常必须检查它是否有价值。 Optional::isPresent
有一个Optional::isPresent
方法。 但是,您经常需要了解相反的情况Optional
空。 没问题,只需使用!opt.isPresent()
吧?
当然,可以这样做,但是if
条件没有反转,则几乎总是更容易理解if
逻辑。 有时,在一连串的通话结束时会弹出Optional
,如果您不需要检查任何内容,则必须下注!
在开始时:
public boolean needsToCompleteAddress(User user) { return !getAddressRepository() .findAddressFor(user) .map(this::canonicalize) .filter(Address::isComplete) .isPresent(); }
在这种情况下,请跳过!
非常容易 从Java 11开始,有一个更好的选择:
public boolean needsToCompleteAddress(User user) { return getAddressRepository() .findAddressFor(user) .map(this::canonicalize) .filter(Address::isComplete) .isEmpty(); }
用'Predicate::not'
反转谓词
说到反转... Predicate
接口具有一个 negate
实例 negate
:它返回一个新的谓词,该谓词执行相同的检查,但是将其结果反转。 不幸的是,我很少设法使用它...
问题是我很少访问Predicate
实例。 更常见的是,我想通过方法的链接来获得这样的实例(并将其反转),但是要使其正常工作,编译器必须知道将对该方法的引用带到何处-没有它,它什么也做不了。 如果您使用(String::isBlank).negate()
,这就是发生的情况:编译器不再知道应在此String::isBlank
什么。 正确指定的种姓可以解决此问题,但要付出什么代价?
虽然有一个简单的解决方案。 不要使用negate
实例negate
,而要使用Java 11中的新静态方法Predicate.not(Predicate<T>)
:
Stream .of("a", "b", "", "c")
已经更好了!
以'Pattern::asMatchPredicate'
作为谓词的正则表达式
有正则表达式吗? 需要过滤数据吗? 怎么样:
Pattern nonWordCharacter = Pattern.compile("\\W"); Stream .of("Metallica", "Motörhead") .filter(nonWordCharacter.asPredicate()) .forEach(System.out::println);
我很高兴找到这种方法! 值得补充的是,这是Java 8中的一种方法。糟糕,我当时错过了它。 Java 11添加了另一个类似的方法: Pattern::asMatchPredicate
。 有什么区别?
asPredicate
检查字符串或字符串的一部分是否与模式匹配(类似于s -> this.matcher(s).find()
)asMatchPredicate
检查整个字符串是否与模式匹配(类似于s -> this.matcher(s).matches()
)
例如,我们有一个检查电话号码的正则表达式,但是它不包含^
和$
来跟踪行的开头和结尾。 然后,以下代码将无法正常运行:
prospectivePhoneNumbers .stream() .filter(phoneNumberPatter.asPredicate()) .forEach(this::robocall);
你有没有发现错误? 诸如" -152 ? +1-202-456-1414"
行将被过滤,因为其中包含有效的电话号码。 另一方面, Pattern::asMatchPredicate
将不允许这样做,因为整个字符串将不再与模式匹配。
自检
这是所有11颗珍珠的概述-您还记得每种方法的作用吗? 如果是这样,则说明您已通过测试。
- 在
String
:
Stream<String> lines()
String strip()
String stripLeading()
String stripTrailing()
boolean isBlank()
String repeat(int)
- 在
Path
:
static Path of(String, String...)
static Path of(URI)
- 在
Files
:
String readString(Path) throws IOException
Path writeString(Path, CharSequence, OpenOption...) throws IOException
Path writeString(Path, CharSequence, Charset, OpenOption...) throws IOException
- 在
InputStream
: static InputStream nullInputStream()
- 在
OutputStream
: static OutputStream nullOutputStream()
- 在
Reader
: static Reader nullReader()
- 在
Writer
: static Writer nullWriter()
- in
Collection
: T[] toArray(IntFunction<T[]>)
- 在
Optional
: boolean isEmpty()
- 在
Predicate
: static Predicate<T> not(Predicate<T>)
- 在
Pattern
: Predicate<String> asMatchPredicate()
玩Java 11!