一、Java8 Lambda表达式
lambda表达式也可称为闭包,允许把函数作为参数参数传递进方法中。可以使代码变得简洁。
1.1语法
(params)->expression或(params)->{statements;}
特征:
可选类型声明:无需声明参数类型,编译器统一识别;
可选的参数圆括号:一个参数无需定义圆括号,多个参数需要定义圆括号;
可选的大括号:主体为一个语句就不需要大括号;
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大哭哦啊好需要指定表达式返回了一个数值。
1.2 lambda表达式实例
public class LambdaTest {
public static void main(String args[]){
LambdaTest test=new LambdaTest();
//=========多参数用括号=============
//类型声明
A add=(int a,int b)->a+b;
//不用类型声明
A subs=(a,b)->a-b;
//大括号中返回语句
A mult=(a,b)->{
return a*b;
};
System.out.println("10+15="+test.operate(10,15,add));
System.out.println("10-15="+test.operate(10,15,subs));
System.out.println("10*15="+test.operate(10,15,mult));
//=========单参数不用括号=============
//参数带括号
B hi1=(message)->System.out.println("hello "+message);
//参数不带 括号
B hi2=message->System.out.println("hello "+message);
hi1.say("Tom");
hi2.say("Jack");
}
interface A{
int operation(int a ,int b);
}
interface B{
void say(String message);
}
private int operate(int a,int b,A ia){
return ia.operation(a,b);
}
}
1.3 变量作用域
lambda表达式只能引用标记了final的外层局部变量,就是说不能再lambda内部修改定义在域外的局部变量,否则会编译错误。
System.out.println(name);
public class LambdaTest {
// static String name="Naland";
public static void main(String args[]) {
LambdaTest test = new LambdaTest();
String name = "Naland";
//参数带括号
B hi1 = (message) -> System.out.println("hello " + message);
//参数不带 括号
B hi2 = message -> {
System.out.println(name + message);
name = "456";
};
hi1.say("Tom");
hi2.say(" Jack");
}
interface B {
void say(String message);
}
}
此段代码会报编译错误,提示name需要被final修饰,或者删除name="456"这一行代码;
二、Java8方法引用
定义:方法引用通过一个方法名来指向一个方法。
优点:方法引用可以使语言的构造简洁,减少冗余代码。
语法:方法引用语法是一对冒号 :: 。
实例:先看下各种方法的引用
public class Computer {
/**
* Supplier是java8的接口,每次调用get()方法时都会调用构造方法创建一个新对象
* @param supplier
* @return
*/
public static Computer create(final Supplier<Computer> supplier){
return supplier.get();
}
public static void office(final Computer computer){
System.out.println("Office "+computer.toString());
}
public void video(){
System.out.println("Video "+this.toString());
}
public void print(final Computer computer){
System.out.println("Print "+ computer.toString());
}
public static void main(String args[]){
//构造器引用包装了Supplier 可用Class::new
//1.构造器引用
Computer computer=Computer.create(Computer::new);
Computer computer1= Computer.create(Computer::new);
Computer computer2= Computer.create(Computer::new);
Computer computer3= Computer.create(Computer::new);
List<Computer>computers= Arrays.asList(computer,computer1,computer2,computer3);
//2.静态方法引用
computers.forEach(Computer::office);
//3.特定类任意对象的方法引用:他的语法Class::method
computers.forEach(Computer::video);
//4.特定对象的方法引用,语法instance::method
final Computer printer=Computer.create(Computer::new);
computers.forEach(printer::print);
}
}
三、Java 8 默认方法
定义:默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。
目的:是为了解决接口的修改与现有的实现不兼容的问题。
语法:方法前加default 关键字
public interface Vehicle {
default void print() {
System.out.println("我是一辆车!");
}
}
调用:
class Car implements Vehicle, FourWheeler {
public void print() {
Vehicle.super.print();
}
}
四、Java8 Stream
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选,排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
4.1何为流?
Stream是一个来自数据的元素队列并支持聚合操作。
元素:是特定类型的对象,形成一个队列。Java中的Stream并不会存储元素,而是按需计算。
数据源:流的来源。可以是集合,数组,I/O channel,产生器generator等。
聚合操作:类似SQL语句一样的操作,比如filter,map,reduce,find,match,sorted等.
与Collection操作不同,Stream操作还有2个基础特征:
PipeLining:中间操作会返回流对象本省。这样许多操作可以串联成一个管道,如同流式风格。这样做可以对操作进行优化,比如延迟执行和短路。
内部迭代:以前集合遍历都是通过Iterator或者foreach的方式,显示的在集合外部进行迭代,这叫做外部迭代。Stream提供了内部迭代,通过访问者模式实现。
4.2 生成流
在java中,集合接口有2种方式生成流:
stream()--为集合创建串行流。
parallelStream()--危机和创建并行流。
List<String>listStrings=Arrays.asList("aaa","bbb","ccc","");
List<String>filetered=listStrings.stream().filter(string->!string.isEmpty()).collect(Collectors.toList());
4.3 forEach
Stream提供了新的方法‘forEach’来迭代流中数据:
listStrings.forEach(System.out::pringln);
4.4 map
map方法用于映射每个元素到对应的 结果,如下:
List<Integer>nums=Arrays.asList(2,3,5,9,7,0);
List<Integer>squaresList=nums.stream().map(i->i*i).distinct().collect(Collectors.toList());
4.5 filter
filter方法用于通过设置条件过滤出元素,如下统计4.2字符串集合空串数量
int count=listStrings.stream().filter(s->s.isEmpty()).count();
4.6 limit
用于获取指定数额的流。下面代码片段用于打印10个随机数
Random random=new Random();
random.ints().limit(10).forEach(System.out::println);
4.7 sorted
sorted 方法用于流排序,对4.6 的随机数集合进行排序
random.ints().limit(10).sorted().forEach(System.out::println);
4.8 并行(parallel)程序
parallelStream 是流并行处理程序的代替方法。以下实例我们使用parallelStream 来输出空字符串的数量:
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
// 获取空字符串的数量
int count = (int) strings.parallelStream().filter(string -> string.isEmpty()).count();
我们可以很容易的在顺序运行和并行直接切换。
五、Java8 中的Optional类
Optional类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回ture,调用get()会返回该对象。
Optional<T>,可以不用显示的进行空值检测。
很好的解决的空指针异常。
实例:
public class Java8Tester {
public static void main(String args[]) {
Java8Tester java8Tester = new Java8Tester();
Integer value1 = null;
Integer value2 = new Integer(10);
// Optional.ofNullable - 允许传递为 null 参数
Optional<Integer> a = Optional.ofNullable(value1);
// Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
Optional<Integer> b = Optional.of(value2);
System.out.println(java8Tester.sum(a, b));
}
public Integer sum(Optional<Integer> a, Optional<Integer> b) {
// Optional.isPresent - 判断值是否存在
System.out.println("第一个参数值存在: " + a.isPresent());
System.out.println("第二个参数值存在: " + b.isPresent());
// Optional.orElse - 如果值存在,返回它,否则返回默认值
Integer value1 = a.orElse(new Integer(0));
//Optional.get - 获取值,值需要存在
Integer value2 = b.get();
return value1 + value2;
}
}
执行以上脚本,输出结果为:
第一个参数值存在:false
第二个参数值存在:true
10