Java 8于2014年3月18日发布,这已经很久了,但仍有许多项目在Java 8上运行。
Java 8 功能的快速概述
Java 8 的一些重要功能是:
- forEach() 方法在 Iterable 接口
- 默认和静态方法在 接口
- 功能接口和 Lambda 表达式
- Java Stream API for Bulk Data Operations on Collections
- Java Time API
- 收集 API 改进
- 竞争 API 改进
- Java IO 改进
让我们简要看看这些Java 8功能,我会提供一些代码片段,以便以简单的方式更好地了解这些功能。
1. forEach() 方法在 Iterable 接口中
每当我们需要穿过一个集合时,我们需要创建一个Iterator,其整个目的是重复重复,然后我们对集合中的每个元素有一个循环中的业务逻辑。
Java 8 在 java.lang.Iterable 界面中引入了 forEach 方法,以便在编写代码时我们专注于商业逻辑。
1package com.journaldev.java8.foreach;
2
3import java.util.ArrayList;
4import java.util.Iterator;
5import java.util.List;
6import java.util.function.Consumer;
7import java.lang.Integer;
8
9public class Java8ForEachExample {
10
11 public static void main(String[] args) {
12
13 //creating sample Collection
14 List<Integer> myList = new ArrayList<Integer>();
15 for(int i=0; i<10; i++) myList.add(i);
16
17 //traversing using Iterator
18 Iterator<Integer> it = myList.iterator();
19 while(it.hasNext()){
20 Integer i = it.next();
21 System.out.println("Iterator Value::"+i);
22 }
23
24 //traversing through forEach method of Iterable with anonymous class
25 myList.forEach(new Consumer<Integer>() {
26
27 public void accept(Integer t) {
28 System.out.println("forEach anonymous class Value::"+t);
29 }
30
31 });
32
33 //traversing with Consumer interface implementation
34 MyConsumer action = new MyConsumer();
35 myList.forEach(action);
36
37 }
38
39}
40
41//Consumer implementation that can be reused
42class MyConsumer implements Consumer<Integer>{
43
44 public void accept(Integer t) {
45 System.out.println("Consumer impl Value::"+t);
46 }
47}
行数可能会增加,但forEach方法有助于将迭代逻辑和业务逻辑分开,从而导致更高的关切分离和更清洁的代码。
界面中的默认和静态方法
如果你仔细阅读forEach method details,你会注意到它是在Iterable接口中定义的,但我们知道接口不能有方法体. 从Java 8开始,接口被增强到具有实现的方法。
1default void forEach(Consumer<? super T> action) {
2 Objects.requireNonNull(action);
3 for (T t : this) {
4 action.accept(t);
5 }
6}
我们知道Java不提供( / 社区 / 教程 / 多重继承 - 在Java),因为它导致了钻石问题
**,所以现在接口将如何处理,因为接口现在类似于抽象类?
解决方案是,编译器在这种情况下会排除一个例外,我们将不得不在实现接口的类中提供实现逻辑。
1package com.journaldev.java8.defaultmethod;
2
3@FunctionalInterface
4public interface Interface1 {
5
6 void method1(String str);
7
8 default void log(String str){
9 System.out.println("I1 logging::"+str);
10 }
11
12 static void print(String str){
13 System.out.println("Printing "+str);
14 }
15
16 //trying to override Object method gives compile-time error as
17 //"A default method cannot override a method from java.lang.Object"
18
19// default String toString(){
20// return "i1";
21// }
22
23}
1package com.journaldev.java8.defaultmethod;
2
3@FunctionalInterface
4public interface Interface2 {
5
6 void method2();
7
8 default void log(String str){
9 System.out.println("I2 logging::"+str);
10 }
11
12}
请注意,这两种接口都具有共同的方法 log() 和实现逻辑。
1package com.journaldev.java8.defaultmethod;
2
3public class MyClass implements Interface1, Interface2 {
4
5 @Override
6 public void method2() {
7 }
8
9 @Override
10 public void method1(String str) {
11 }
12
13 //MyClass won't compile without having it's own log() implementation
14 @Override
15 public void log(String str){
16 System.out.println("MyClass logging::"+str);
17 Interface1.print("abc");
18 }
19
20}
正如你可以看到的,‘Interface1’具有静态方法实现,用于‘MyClass.log()’方法实现。Java 8在 Collection API中使用了 default和 static方法,并且添加了默认方法,以便我们的代码保持反向兼容性。
如果等级中的任何一个类都有具有相同签名的方法,那么默认方法就变得无关紧要了。 对象是基本类,所以如果我们在接口中有平等(), hashCode()默认方法,它就变得无关紧要了。
有关Java 8界面变更的完整细节,请参阅Java 8界面变更(/community/tutorials/java-8-interface-changes-static-method-default-method)。
功能界面和Lambda表达式
如果你注意到上面的界面代码,你会注意到 @FunctionalInterface 注释. 功能界面是 Java 8 中引入的一种新概念。
@FunctionalInterface 注释是避免在功能界面中随机添加抽象方法的工具,你可以把它想象成 @Override 注释,并且使用它是最好的做法。
功能界面的主要优点之一是使用 lambda 表达式来实例化它们的可能性. 我们可以实例化一个界面用一个 [匿名类]( / 社区 / 教程 / java - 内部类),但代码看起来很大。
1Runnable r = new Runnable(){
2 @Override
3 public void run() {
4 System.out.println("My Runnable");
5 }};
由于功能界面只有一种方法, lambda 表达式可以很容易地提供方法实现。我们只需要提供方法论点和业务逻辑。
1Runnable r1 = () -> {
2 System.out.println("My Runnable");
3 };
如果你在方法实现中有单个陈述,我们也不需要弯曲的轴承,例如,上面的Interface1匿名类可以使用 lambda 以以下方式实例化:
1Interface1 i1 = (s) -> System.out.println(s);
2
3i1.method1("abc");
因此,lambda表达式是轻松创建功能接口的匿名类的一种方式.使用lambda表达式没有运行时间的好处,所以我会谨慎地使用它,因为我不介意写几行额外的代码。
新包「java.util.function」被添加了大量的功能界面,为 lambda 表达式和方法引用提供目标类型。
您可以阅读完整的教程在 [Java 8 Lambda 表达式教程]( / 社区 / 教程 / Java-8 - 功能界面)。
Java Stream API 用于集合的大量数据操作
Java 8 中添加了一种新的java.util.stream
来执行类似于集合的过滤/地图/减少操作. 流 API 将允许连续和并行执行. 这对我来说是最好的功能之一,因为我用 Collections 工作很多,通常用大数据,我们需要根据一些条件过滤它们。
收集界面已被扩展到 stream() 和 parallelStream() 默认方法,以获得流序列和并行执行。
1package com.journaldev.java8.stream;
2
3import java.util.ArrayList;
4import java.util.List;
5import java.util.stream.Stream;
6
7public class StreamExample {
8
9 public static void main(String[] args) {
10
11 List<Integer> myList = new ArrayList<>();
12 for(int i=0; i<100; i++) myList.add(i);
13
14 //sequential stream
15 Stream<Integer> sequentialStream = myList.stream();
16
17 //parallel stream
18 Stream<Integer> parallelStream = myList.parallelStream();
19
20 //using lambda with Stream API, filter example
21 Stream<Integer> highNums = parallelStream.filter(p -> p > 90);
22 //using lambda in forEach
23 highNums.forEach(p -> System.out.println("High Nums parallel="+p));
24
25 Stream<Integer> highNumsSeq = sequentialStream.filter(p -> p > 90);
26 highNumsSeq.forEach(p -> System.out.println("High Nums sequential="+p));
27
28 }
29
30}
如果你要运行以上示例代码,你会得到这样的输出:
1High Nums parallel=91
2High Nums parallel=96
3High Nums parallel=93
4High Nums parallel=98
5High Nums parallel=94
6High Nums parallel=95
7High Nums parallel=97
8High Nums parallel=92
9High Nums parallel=99
10High Nums sequential=91
11High Nums sequential=92
12High Nums sequential=93
13High Nums sequential=94
14High Nums sequential=95
15High Nums sequential=96
16High Nums sequential=97
17High Nums sequential=98
18High Nums sequential=99
请注意,平行处理值不顺序,因此在处理大型集合时,平行处理非常有用。
在本文中无法覆盖流程 API 的所有内容,您可以在 Java 8流程 API 示例教程阅读流程 API 的所有内容。
5. Java 时间 API
在 Java 中,没有日期和时间的标准方法或 API 在 Java 中。在 Java 8 中,一个很好的补充是java.time
包,它将简化 Java 中的时间工作过程。
只要看 Java Time API 套件,我可以感觉到它们将非常容易使用,它有几个子套件 java.time.format 提供类来打印和分析日期和时间, java.time.zone 支持时区及其规则。
新的 Time API 更喜欢为每周的几个月和几天使用整数常数。 其中一个有用的类是 DateTimeFormatter 用于将 DateTime 对象转换为字符串。 对于完整的教程,请转到 Java Date Time API 示例教程。
收集 API 改进
我们已经看到 forEach() 方法和收藏流 API. 收藏 API 中添加的一些新方法是:
Iterator
默认方法forEachRemaining(消费者行动)
对每个剩余元素执行给定的操作,直到所有元素都被处理或该操作丢弃了例外Collection
默认方法removeIf(Predicate filter)
删除这个集合中满足给定的预言的所有元素Collection
spliterator()
方法返回可以用来连续或并行穿过元素的 Spliterator 实例- Mapreplace
All()
,compute()
,merge()
方法 - HashMap 类与密钥碰撞 的性能改进
竞争对手 API 改进
一些重要的竞争性 API 增强是:
ConcurrentHashMap
计算(), forEach(), forEachEntry(), forEachKey(), forEachValue(), merge(), reduce() 和 search() 方法- `CompletableFuture' 可能被明确完成(设置其值和状态)。
Executors
newWorkStealingPool()
方法以使用所有可用的处理器创建一个工作窃取线程池作为其目标平行度水平
8. Java IO 改进
我所知道的一些改进是:
Files.list(Path dir)
返回一个懒散的人口流,其元素是目录中的条目Files.lines(Path path)
读取文件中的所有行作为流Files.find()
返回一个流被懒散的人口流与 Path 通过搜索根植于给定起始文件的文件树中的文件BufferedReader.lines()
返回流,其元素是从这个 BufferedReader 读取的行。
Java 8 核心 API 改进
一些可能有用的不同类型的 API 改进是:
- ThreadLocal静态方法 withInitial(供应商)以轻松地创建实例
- 比较器界面已经扩展了许多默认和静态方法自然排序,逆顺序,等等
- min(),max()和 sum()方法在 Integer,长和双包装类 4.逻辑(),逻辑Or()和逻辑Xor()方法在布尔文类。
如果我错过了Java 8的一些重要功能,请通过评论告诉我。