JDK 为什么在不断变化?
要么改变,要么衰亡。
Java8 为开发者提供更多的工具和概念。
更快、更简洁、更易于维护的处理编程问题。
主要变化
- 方法作为一等公民
Scala、Groovy 等语言已经实践证明。
让方法作为一等值,可以扩充程序员的工具库,让编程变得简单。
- lambda作为一等公民
Java8 还体现了更广义的将函数作为值得思想,将 lambda 作为一等值。
- 流
传统的 java 对于集合的创建和操作,相对来说比较麻烦。
且无法充分地利用多核CPU。
- 默认方法
interface
接口中可以定义默认方法。
- NULL 的处理
Optional<T>
类对于 null 的处理。
- 模式匹配
可以将模式匹配看作是 switch 的扩展形式,同时将一个数据类型分解成元素。
New Features
Lambda
Lambda 表达式内容比较重要,放在单独的一篇进行讲解。
Lambda expression is anonymous function.
- old way
public void old() {
Runnable r = new Runnable() {
public void run() {
System.out.println("Hello World!");
}
};
new Thread(r).start();
}
- use lambda
new Thread(() -> System.out.println("Lambda Hello World!")).start();
lambda expression grammar
(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
statment1;
statment2;
//.............
return statmentM;
}
1、No parameters.
() -> { //..... };
2、One parameter, can leave out the parameter type, javac can deduce it from the context.
param1 -> {
statment1;
statment2;
//.............
return statmentM;
}
3、Only one statement, can leave out the {}.
param1 -> statment
4、Leave out the parameters’ type.
(param1,param2, ..., paramN) -> {
statment1;
statment2;
//...
return statmentM;
}
demo
- Person.java
public interface Person {
void say(String string);
}
- call it use lambda
public static void main(String[] args) {
Person h = str -> System.out.println(str);
h.say("Hello World");
}
- result
Hello World
interface default method
- Person.java
public interface Person {
void say();
default void eat() {
System.out.println("eat...");
}
}
- Student.java
public class Student implements Person {
@Override
public void say() {
System.out.println("say...");
}
}
- test
public static void main(String[] args) {
Student student = new Student();
student.say();
student.eat();
}
- result
say...
eat...
Process finished with exit code 0
method reference
1、static method: ClassName::methodName
- test
public static void main(String[] args) {
List<String> strs = Arrays.asList("aa","bb","cc");
strs.forEach(System.out::println);
}
- result
aa
bb
cc
Process finished with exit code 0
2、instance method: instanceRefence::methodName
- HelloWorld.java
public class HelloWorld {
void print(){
System.out.println("instanceRefence::methodName");
}
public void printInfo(){
System.out.println("printInfo");
//instance method reference
new Thread(this::print).start();
}
}
- test
public static void main(String[] args) {
HelloWorld helloWorld = new HelloWorld();
helloWorld.printInfo();
}
- result
printInfo
instanceRefence::methodName
Process finished with exit code 0
3、constructor method: Class::new
- User.java
public class User {
String username;
User(String username){
this.username = username;
}
public String getUsername(){
return username;
}
}
- HelloWorld.java
public class HelloWorld {
@FunctionalInterface
interface UserFactory<T extends User> {
T create(String username);
}
private void test() {
UserFactory<User> uf = User::new;
List<User> users = new ArrayList<>();
for (int i = 0; i < 5; ++i) {
users.add(uf.create("user"+i));
}
users.stream().map(User::getUsername).forEach(System.out::println);
}
}
- test
public static void main(String[] args) {
HelloWorld helloWorld = new HelloWorld();
helloWorld.test();
}
- result
user0
user1
user2
user3
user4
Process finished with exit code 0
Repeating Annotations
- RepeatingAnnotationsTest.java
public class RepeatingAnnotationsTest {
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Filters {
Filter[] value();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Filters.class)
public @interface Filter {
String value();
}
@Filter("filter1")
@Filter("filter2")
public interface Filterable {
}
public static void main(String[] args) {
for (Filter filter : Filterable.class.getAnnotationsByType(Filter.class)) {
System.out.println(filter.value());
}
}
}
result
filter1
filter2
Better Type Inference
public class TypeInference<T> {
public static <T> T defaultValue() {
return null;
}
public T getOrDefault(T value, T defaultValue) {
return (value != null) ? value : defaultValue;
}
@Test
public void betterTest() {
final TypeInference<String> value = new TypeInference<>();
String result = value.getOrDefault("22", TypeInference.defaultValue());
System.out.println(result); //22
}
}
More useful annotation
Java 8拓宽了注解的应用场景。现在,注解几乎可以使用在任何元素上:局部变量、接口类型、超类和接口实现类,甚至可以用在函数的异常定义上。
- MoreUsefulAnnotationTest.java
public class MoreUsefulAnnotationTest {
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
public @interface NonEmpty {
}
public static class Holder<@NonEmpty T> extends @NonEmpty Object {
public void method() throws @NonEmpty Exception {
}
}
@SuppressWarnings("unused")
public static void main(String[] args) {
final Holder<String> holder = new @NonEmpty Holder<String>();
@NonEmpty Collection<@NonEmpty String> strings = new ArrayList<>();
}
}
Lib
Optional
Google Guava 引入了 Optionals 类来解决 NullPointerException,从而避免源码被各种 null 检查污染,以便开发者写出更加整洁的代码。Java 8也将Optional加入了官方库。
Optional仅仅是一个容器:存放T类型的值或者null。它提供了一些有用的接口来避免显式的null检查。
- nullTest()
@Test
public void nullTest() {
Optional< String > fullName = Optional.ofNullable( null );
System.out.println( "Full Name is set? " + fullName.isPresent() );
System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) );
System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
}
result
Full Name is set? false
Full Name: [none]
Hey Stranger!
- notNullTest()
@Test
public void notNullTest() {
Optional< String > fullName = Optional.ofNullable( "ryo" );
System.out.println( "Full Name is set? " + fullName.isPresent() );
System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) );
System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
}
result
Full Name is set? true
Full Name: ryo
Hey ryo!
Streams
新增的Stream API(java.util.stream)将生成环境的函数式编程引入了Java库中。 这是目前为止最大的一次对Java库的完善,以便开发者能够写出更加有效、更加简洁和紧凑的代码。
- StreamsTest.java
public class StreamsTest {
private enum Status {
OPEN, CLOSED
}
private static final class Task {
private final Status status;
private final Integer points;
Task(final Status status, final Integer points) {
this.status = status;
this.points = points;
}
public Integer getPoints() {
return points;
}
public Status getStatus() {
return status;
}
@Override
public String toString() {
return String.format("[%s, %d]", status, points);
}
}
}
- test
@Test
public void totalTest() {
final Collection<Task> tasks = Arrays.asList(
new Task(Status.OPEN, 5),
new Task(Status.OPEN, 13),
new Task(Status.CLOSED, 8)
);
// Calculate total points of all active tasks using sum()
final long totalPointsOfOpenTasks = tasks
.stream()
.filter(task -> task.getStatus() == Status.OPEN)
.mapToInt(Task::getPoints)
.sum();
System.out.println(totalPointsOfOpenTasks); //18
}
@Test
public void parallelTest() {
final Collection<Task> tasks = Arrays.asList(
new Task(Status.OPEN, 5),
new Task(Status.OPEN, 13),
new Task(Status.CLOSED, 8)
);
final double totalPoints = tasks
.stream()
.parallel()
.map(task -> task.getPoints()) // or map( Task::getPoints )
.reduce(0, Integer::sum);
System.out.println("Total points (all tasks): " + totalPoints); //Total points (all tasks): 26.0
}
@Test
public void groupByTest() {
final Collection<Task> tasks = Arrays.asList(
new Task(Status.OPEN, 5),
new Task(Status.OPEN, 13),
new Task(Status.CLOSED, 8)
);
// Group tasks by their status
final Map< Status, List< Task >> map = tasks
.stream()
.collect( Collectors.groupingBy( Task::getStatus ) );
System.out.println( map ); //{OPEN=[[OPEN, 5], [OPEN, 13]], CLOSED=[[CLOSED, 8]]}
}
@Test
public void percentTest() {
final Collection<Task> tasks = Arrays.asList(
new Task(Status.OPEN, 5),
new Task(Status.OPEN, 13),
new Task(Status.CLOSED, 8)
);
// Calculate total points of all tasks
final double totalPoints = tasks
.stream()
.parallel()
.map( task -> task.getPoints() ) // or map( Task::getPoints )
.reduce( 0, Integer::sum );
// Calculate the weight of each tasks (as percent of total points)
final Collection< String > result = tasks
.stream() // Stream< String >
.mapToInt( Task::getPoints ) // IntStream
.asLongStream() // LongStream
.mapToDouble( points -> points / totalPoints ) // DoubleStream
.boxed() // Stream< Double >
.mapToLong( weigth -> ( long )( weigth * 100 ) ) // LongStream
.mapToObj( percentage -> percentage + "%" ) // Stream< String>
.collect( Collectors.toList() ); // List< String >
System.out.println(result); //[19%, 50%, 30%]
}
Date/Time API(JSR 310)
Java 8引入了新的Date-Time API(JSR 310)来改进时间、日期的处理。
Joda-Time,可以替代Java的时间管理API。
Nashorn JavaScript
Java 8提供了新的Nashorn JavaScript引擎,使得我们可以在JVM上开发和运行js应用。
Nashorn JavaScript引擎是 javax.script.ScriptEngine
的另一个实现版本,这类Script引擎遵循相同的规则,允许Java和javascript交互使用,例子代码如下:
- NashornJSTest.java
public class NashornJSTest {
@Test
public void jsTest() throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName( "JavaScript" );
System.out.println( engine.getClass().getName() );
System.out.println( "Result:" + engine.eval( "function f() { return 1; }; f() + 1;" ) );
}
}
result:
jdk.nashorn.api.scripting.NashornScriptEngine
Result:2.0
Base64
对Base64编码的支持已经被加入到Java 8官方库中.
- base64Test()
@Test
public void base64Test() {
final String text = "Base64 finally in Java 8!";
final String encoded = Base64
.getEncoder()
.encodeToString(text.getBytes(StandardCharsets.UTF_8));
System.out.println(encoded);
final String decoded = new String(
Base64.getDecoder().decode(encoded),
StandardCharsets.UTF_8);
System.out.println(decoded);
}
result
QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ==
Base64 finally in Java 8!
ParallelArrays
- parallelArraysTest()
/**
* 使用parallelSetAll()方法生成20000个随机数,然后使用parallelSort()方法进行排序。这个程序会输出乱序数组和排序数组的前10个元素。
*/
@Test
public void parallelArraysTest() {
long[] arrayOfLong = new long[20000];
Arrays.parallelSetAll(arrayOfLong,
index -> ThreadLocalRandom.current().nextInt(1000000));
Arrays.stream(arrayOfLong).limit(10).forEach(
i -> System.out.print(i + " "));
System.out.println();
Arrays.parallelSort(arrayOfLong);
Arrays.stream(arrayOfLong).limit(10).forEach(
i -> System.out.print(i + " "));
System.out.println();
}
result:
395659 19377 864569 289077 710936 742196 922967 850922 701156 551843
7 17 49 111 116 173 194 260 344 396