函数式编程(Java 8)
在Java8中,功能编程和lambda被添加为语言功能。函数式编程可与Java中的Streamsnull安全monads(Optional)一起使用,如下所示:
流(Java 8)
对于一般的计算机程序,通常必须使用值列表,并对每个值执行给定的转换。在Java 8之前,您必须使用for循环进行此转换,但是从现在开始,您可以使用Streams以下方法:
Stream.of("hello", "great")
.map(s -> s + " world")
.forEach(System.out::println);
hello world
great world
该map函数以一个lambda作为输入,它将应用于流中的所有元素。
Streams可以在Lists,Sets和Maps(通过转换)上工作。
Optional(Java 8)
Java中的另一个常见问题是Null Pointer Exceptions。因此,Java引入了Optional 这是一个monad,它包装了一个可能为null或不为null的引用。可以通过函数性方式将更新应用于此Optional:
Optional.of(new Random().nextInt(10))
.filter(i -> i % 2 == 0)
.map(i -> "number is even: " + i)
.ifPresent(System.out::println);
number is even: 6
在上面的代码段中,我们创建一个随机数,将其包装在Optional对象中,然后仅打印偶数。
JShell(Java 9)
我们有一个Java的REPL,它的名字叫JShell!简而言之,JShell允许在不编写和编译完整Java类的情况下尝试Java代码段。相反,您可以一次执行一个命令,然后立即看到结果。这是一个简单的例子:
$ <JDK>/bin/jshell
jshell> System.out.println("hello world")
hello world
长期以来,熟悉JavaScript或Python等解释型语言的人们都对REPL感到满意,但到目前为止,Java中缺少此功能。JShell允许定义变量,但也可以定义更复杂的实体,例如多行函数,类和执行循环。而且,JShell支持自动完成,如果您不知道给定Java类提供的确切方法,该功能将非常有用。
不可变集合的工厂方法(Java 9)
ListsJava的简单初始化早已丢失,但现在已经过去了。以前,您必须执行以下操作:
jshell> List<Integer> list = Arrays.asList(1, 2, 3, 4)
list ==> [1, 2, 3, 4]
现在将其简化如下:
jshell> List<Integer> list = List.of(1, 2, 3, 4)
b ==> [1, 2, 3, 4]
List,Set和Mapof(…)存在这种奇特的方法。它们都只用一行简单的代码就创建了一个不变的对象。
使用var(Java 10)进行 类型推断
Java 10引入了新的var关键字,该关键字允许省略变量的类型。
jshell> var x = new HashSet<String>()
x ==> []
jshell> x.add("apple")
$1 ==> true
在上面的代码段中,编译器x可以将的类型推断为HashSet。
此功能有助于减少样板代码并提高可读性。但是,它有一些局限性:var只能在方法主体内部使用,并且编译器将在编译时推断类型,因此所有内容仍为静态类型。
单一源文件启动(Java 11)
要运行一个 Java 源代码必须先编译(javac),再运行(java),两步执行动作。而在Java 11中,通过一个 java 命令就直接搞定了,如以下所示:
Main.java:
public class Main {
public static void main(String[] args) {
System.out.println("hello world");
}
}
$ java ./Main.java
hello world
对于仅由一个Java类组成的简单启动程序或实验,此功能更方便实用。
Switch表达式(Java 12)
Java 12为我们带来了Switch表达式。这是该表达式与旧的switch语句有何不同的快速展示。
在老switch语句定义了程序的流程:
jshell> var i = 3
jshell> String s;
jshell> switch(i) {
...> case 1: s = "one"; break;
...> case 2: s = "two"; break;
...> case 3: s = "three"; break;
...> default: s = "unknown number";
...> }
jshell> s
s ==> "three"
相反,新的switch表达式返回一个值:
jshell> var i = 3;
jshell> var x = switch(i) {
...> case 1 -> "one";
...> case 2 -> "two";
...> case 3 -> "three";
...> default -> "unknown number";
...> };
x ==> "three"
总而言之,旧的switch语句用于程序流,新的switch表达式解析为一个值。
这个新的switch语句是一种映射函数:有一个输入(在上述情况下i),有一个输出(在此x),这实际上是一种模式匹配功能。
需要注意的几件事:
1).我们使用箭头 -> 代替双点
2).不需要 break
3).考虑所有可能的情况时,可以省略默认情况
要在Java 12中启用此功能,请使用 --enable-preview --source 12
Text Block (Java 13)
text block,文本块,是一个多行字符串文字,它避免了对大多数转义序列的需要,以可预测的方式自动格式化字符串,并在需要时让开发人员控制格式。
我们以前从外部copy一段文本串到Java中,会被自动转义,如有一段以下字符串:
<html>
<body>
<p>Hello, world</p>
</body>
</html>
将其复制到Java的字符串中,会展示成以下内容:
"<html>\n"
" <body>\n"
" <p>Hello, world</p>\n"
" </body>\n"
"</html>\n";
即被自动进行了转义,这样的字符串看起来不是很直观,在JDK 13中,就可以使用以下语法了:
"""
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
使用"""作为文本块的开始符合结束符,在其中就可以放置多行的字符串,不需要进行任何转义。看起来就十分清爽了
Record类型(Java 14)
record的出现是为了解决java啰嗦的用来作为数据的承载类(entity层),例如get、set、toString等方法
jshell> record Employee (String name, int age, String department) {}
| created record Employee
jshell> var x = new Employee("Anne", 25, "Legal");
x ==> Employee[name=Anne, age=25, department=Legal]
jshell> x.name()
$2 ==> "Anne"
Scala对于案例类具有类似的功能,对于Kotlin具有数据类具有类似的功能。到目前为止,在Java中,许多开发人员都使用Lombok,它提供了许多现在受recordsJava 14启发的功能。
instanceof (Java 14)
Java的早期版本已经包含instanceof关键字,但要检查s类型是否为String,然后再次对其进行强制转换以获取其长度。
Object obj = new String("hello");
if (obj instanceof String) {
System.out.println("String length: " + ((String)obj).length());
}
现在使用Java 14,编译器可以在instanceof check之后自动推断类型:
Object obj = new String("hello");
if (obj instanceof String mystr) {
System.out.println("String length: " + mystr.length());
}
密封的类(Java 15)
使用sealed关键字,您可以限制哪些类可以扩展给定的类或接口。这是一个例子:
public sealed interface Fruit permits Apple, Pear {
String getName();
}
public final class Apple implements Fruit {
public String getName() { return "Apple"; }
}
public final class Pear implements Fruit {
public String getName() { return "Pear"; }
}
这是朝着完全支持的模式匹配的方向迈出的重要一步,在该模式下,您可以像对待枚举一样对待类。此sealed功能与switch前面说明的新表达式很好地结合在一起。