lambda与stream是java8中比较重要两个新特性,lambda表达式采用一种简洁的语法定义代码块,允许我们将行为传递到函数中。之前我们想将行为传递到函数中,仅有的选择是使用匿名内部类,现在我们可以使用lambda表达式替代匿名内部类。在学习lambda表达式之前,建议各位看官先去学习一下匿名内部类(JAVA基础知识|内部类)。

stream提供了很多有用的api,方便了我们对集合的操作

一、lambda表达式

基本语法:
(parameters) -> expression

(parameters) ->{ statements; }

 

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表达式使用

2.1、在for循环中使用

package com.my.controller;

import junit.framework.TestCase;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

/**
 * description:{description}
 * author:jyy
 * date:2018-01-09 16:43
 * modify:{modify}
 */
public class AppTest extends TestCase {

    @Test
    public void test() {

        List<String> list = new ArrayList<>();
        list.add("北京");
        list.add("上海");
        list.add("广州");
        list.add("深圳");

        for (String str : list) {
            System.out.println(str);
        }

        System.out.println("=================");

        list.forEach(str -> System.out.println(str));

    }

}

执行结果:

北京
上海
广州
深圳
=================
北京
上海
广州
深圳

2.2、替代匿名内部类使用

我们使用JAVA基础知识|内部类中的try catch示例

package com.my.controller;

import junit.framework.TestCase;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

/**
 * description:{description}
 * author:jyy
 * date:2018-01-09 16:43
 * modify:{modify}
 */
public class AppTest extends TestCase {

    @Test
    public void test() {

        //匿名内部类
        new ExceptionTemplate().execute(new CatchExceptionable() {
            @Override
            public void catchException() {
                System.out.println("代码");
            }
        });

        //lambda表达式
        new ExceptionTemplate().execute(() -> System.out.println("代码"));
    }

}

2.3、lambda表达式与Comparator类结合使用

package com.my.controller;

import junit.framework.TestCase;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * description:{description}
 * author:jyy
 * date:2018-01-09 16:43
 * modify:{modify}
 */
public class AppTest extends TestCase {

    @Test
    public void test() {

        List<String> list = new ArrayList<>();
        list.add("BeiJing");
        list.add("ShangHai");
        list.add("GuangZhou");
        list.add("ShenZhen");

        list.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        list.forEach(str -> System.out.println(str));

        System.out.println("==============");

        List<String> list2 = new ArrayList<>();
        list2.add("BeiJing");
        list2.add("ShangHai");
        list2.add("GuangZhou");
        list2.add("ShenZhen");

        //list2.sort((String o1,String o2) -> o1.compareTo(o2));
        Comparator<String> comparator =(String o1,String o2) -> o1.compareTo(o2);
        list2.sort(comparator);
        list2.forEach(str -> System.out.println(str));

    }
}

执行结果:

BeiJing
GuangZhou
ShangHai
ShenZhen
==============
BeiJing
GuangZhou
ShangHai
ShenZhen

2.4、 lambda不能访问非final的局部变量

之前我们说过匿名内部类不能访问非final的局部变量,其实lambda也有这个限制,lambda与匿名内部类在访问外部变量时,都不允许有修改变量的倾向。

因为实例变量存在堆中,而局部变量是在栈上分配,lambda 表达(匿名类) 会在另一个线程中执行。如果在线程中要直接访问一个局部变量,可能线程执行时该局部变量已经被销毁了,这会导致一些问题。

Java 8 的 lambda 可以捕获什么变量呢?

(1). 捕获实例或静态变量是没有限制的 (可认为是通过 final 类型的局部变量 this 来引用前两者);

(2). 捕获的局部变量必须显式的声明为 final或实际效果的final 类型。

也就是在 Java 8 下,即使局部变量未声明为 final 类型,一旦在匿名类中访问了一下就被强型加上了 final 属性,所以后面就无法再次赋值了。换句话说,如果在匿名类或 lambda 表达式中访问的局部变量,如果不是 final 类型的话,编译器自动加上 final 修饰符。

    public DocApplicationTests(){
        String str="123";
        Consumer<String> consumer = a->System.out.print(str);
        //str="345";//编译报错
    }

三、流stream

Java 8 中的stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。stream API 借助于同样新出现的 lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势

生成流的两种方式:

  • stream() − 为集合创建串行流。
  • parallelStream() − 为集合创建并行流。

下面我们就来使用stream提供的各种API:

3.1、筛选和切片

方法 描述
filter 从流中过滤元素
distinct 通过流所生成的元素的hashCode()和equals()方法去重
limit 截断流,选取前n个元素
skip 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足n个,则返回一个空流

 

package com.my.po;

/**
 * description:{description}
 * author:jyy
 * date:2018-02-11 11:06
 * modify:{modify}
 */
public class Employee {
    private String id;
    private String name;
    private double salary;
    private String sex;

    public Employee(String id, String name, double salary,String sex) {
        this.id = id;
        this.name = name;
        this.salary = salary;
        this.sex=sex;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", salary=" + salary +
                ", sex='" + sex + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Employee employee = (Employee) o;

        return id.equals(employee.id);
    }

    @Override
    public int hashCode() {
        return id.hashCode();
    }
}
View Code

相关文章: