java 8新特性
- java 8 是java语言开发的一个主要版本, Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。
新特性
- Lambda 表达式 是指允许把函数作为一个方法的参数(函数作为参数传递到方法中)
- 方法引用 是指用提供了非常有用的语法,可以直接引用已有的java类或对象(实例)的方法或构造器。与Lambda联合使用,方法引用可以使语言的结构更加紧凑简介,减少冗余代码
- 默认方法 是指方法就是一个在借口里面有了一个实现的方法
- 新工具 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
- Stream API 新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
- Date Time API 加强了对日期与时间的处理
- Optional类 Optional类已经成为了java 8类库的一部分,用来解决空指针异常
- Nashorn, JavaScript 引擎 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
1.Lambda 表达式
Lambda 表达式,也可以称为闭包,它是推动java8发布的重要特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)
使用Lambda表达式可以使代码变的更加简洁紧凑
语法
Lambda表达式的语法格式如下
(parameters) -> expression
或
(parameters) ->{ statements; }
以下是lambda表达式的重要特征
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号
- 可选的大括号: 如果一个主体包含了一个语句,就不需要大括号
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回一个数值
Lambda 表达式简单例子
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
基本的Lambda例子
- for 循环的写法
@Test
public void testLambda() {
String[] strings = {"淘宝", "京东",
"亚马逊", "谷歌", "百度", "美团",
"天猫", "腾讯", "万达"};
List<String> list = Arrays.asList(strings);
// 以前的循环形式
for (String s : list) {
System.out.print(s);
}
// 使用 lambda 表达式以及函数操作(functional operation)
System.out.println("");
list.forEach((string) -> System.out.print(string + ";"));
System.out.println("");
// 在java 8 中使用双冒号操作符(double colon operator)
list.forEach(System.out::print);
}
正如看到的,lambda表达式可以将我们的代码缩减到一行 ,同时Lambda的功能很强大 ,如实现Runnable接口的示例
// 使用匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello world 1.1");
}
}).start();
// 使用 lambda expression
new Thread(() -> System.out.println("hello world 1.2")).start();
// 使用匿名内部类
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("hello world 2.1");
}
};
Runnable r = () -> System.out.println("hello world 2.2");
runnable.run();
r.run();
Runnable 的 lambda表达式,使用块格式,将五行代码转换成单行语句
使用Lambda排序集合
在java中Comparator 类被用来排序集合,在下面的例子中 我们根据name,suname, name长度来进行排序
String[] players = {"Rafael Nadal", "Novak Djokovic",
"Stanislas Wawrinka", "David Ferrer",
"Roger Federer", "Andy Murray",
"Tomas Berdych", "Juan Martin Del Potro",
"Richard Gasquet", "John Isner"};
// 使用匿名内部类来根据那么排序
Arrays.sort(players, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// 小于返回负数 相等返回0 大于返回正数
return (o1.compareTo(o2));
}
});
// 使用lambdas,可以通过下面的代码实现同样的功能:
Comparator<String> comparator = (String a1, String a2) -> (a1.compareTo(a2));
Arrays.sort(players, comparator);
// 也可以使用下面的形式
Arrays.sort(players, (String s1, String s2) -> (s1.compareTo(s2)));
// 同时使用lambda表达式的for循环
List<String> list = Arrays.asList(players);
list.forEach((string) -> System.out.print(string + ";"));
System.out.println("");
list.forEach(System.out::print);
当然lambda表达式还有很多的用法 ,我只是在这里举例几个简单的例子
2.方法引用
- 方法引用通过方法的名字来指向一个方法
- 方法引用可以使语言的结构更加经凑,减少冗余代码
- 方法引用使用一对冒号" : : "
- 方法引用和lambda表达式一样 都是用来简化开发的
方法引用怎么使用
下来说一下方法引用使用到的操作符"::" ,这个操作符把方法引用分成两边,左边是类名或者某个对象的引用,右边是方法名或者是"new" (构造器引用是时用到)
以下三种引用
- 引用方法
- 引用构造器
- 引用数组
可以发现,方法引用可以引用的不止是方法,就像TCP/IP协议并不只有TCP/IP协议
引用方法
引用方法有下面几种形式
- 对象应用::实例方法名
- 类名::静态方法名
- 类名::实例方法名
对象引用::实例方法名
有个函数式接口Consumer,里面有个抽象方法accept能够接收一个参数但是没有返回值,这个时候我想实现accept方法,让它的功能为打印接收到的那个参数,
Consumer<String> consumer = System.out::println;
consumer.accept("This is Major Tom");
System.out就是一个PrintStream类型的对象引用,而println则是一个实例方法名,需要注意的是没有括号的哟。其中Consumer是Java内置函数式接口,下面的例子用到的都是Java内置函数式接口。Consumer中的唯一抽象方法accept方法参数列表与println方法的参数列表相同,都是接收一个String类型参数
类名::静态方法名
//Function<Long, Long> f = x -> Math.abs(x);
Function<Long, Long> f = Math::abs;
Long result = f.apply(-3L);
Math是一个类而abs为该类的静态方法。Function中的唯一抽象方法apply方法参数列表与abs方法的参数列表相同,都是接收一个Long类型参数。
类名::实例方法名
//BiPredicate<String, String> b = (x,y) -> x.equals(y);
BiPredicate<String, String> b = String::equals;
b.test("abc", "abcd");
String是一个类而equals为该类的定义的实例方法。BiPredicate中的唯一抽象方法test方法参数列表与equals方法的参数列表相同,都是接收两个String类型参数。
方法引用实例
List<String> list = new ArrayList<>();
list.add("Google");
list.add("Runoob");
list.add("Taobao");
list.add("Baidu");
list.add("Sina");
list.forEach(System.out::println);