一、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