Lambda表达式

Lambda表达式

简介

	lambda表达式可以用非常少的代码实现抽象方法。lambda表达式不能独立执行,必须实现函数式接口,并且会返回一个函数式接口的对象。

语法:

 () -> 结果表达式
参数 -> 结果表达式
(参数1,参数2,参数3) -> {结果表达式}

实现函数式接口

实现无参函数式接口

定义一个Book类型的抽象类,类中有一个获取名称的抽象方法,并用lambda来实现
public interface Book {

    String getName();
}

 public static void main(String[] args) {

        Book book = () -> "lambda 实现book接口";

        System.out.println(book.getName());
    }

实现有参函数式接口

定义一个Book类型的抽象类,该抽象类中有一折扣过的书价格方法。
public interface Book {

    BigDecimal getPrice(double discount, BigDecimal price);
}

   public static void main(String[] args) {


        Book book = (discount, price) -> BigDecimal.valueOf(discount).multiply(price);

        System.out.println("最终折扣过的价格是:"+book.getPrice(0.8, BigDecimal.valueOf(32.5)));

        // 最终折扣过的价格是:26.00
    }

调用外部变量

lambda表达式无法更改局部变量的值,但是却可以更改外部类的成员变量的值。
无法更改局部变量的值
public interface Book {

    BigDecimal getPrice(double discount, BigDecimal price);
}

  public static void main(String[] args) {

        BigDecimal methodPrice = BigDecimal.ZERO;

        Book book = (discount, price) -> {
            BigDecimal price1 = BigDecimal.valueOf(discount).multiply(price);

            methodPrice = price1; // 此处会报编译错误
            return price1;
        };

        System.out.println("最终折扣过的价格是:"+book.getPrice(0.8, BigDecimal.valueOf(32.5)));

        // 最终折扣过的价格是:26.00
    }

/*
* 当然也可以使用AtomicReference来更改局部变量
**/

 public static void main(String[] args) {

        /**
         * AtomicReference类提供了一个可以原子读写的对象引用变量。
         * 原子意味着尝试更改相同AtomicReference的多个线程(例如,使用比较和交换操作)不会使AtomicReference最终达到不一致的状态。
         */
        AtomicReference<BigDecimal> methodPrice = new AtomicReference<>(BigDecimal.ZERO);

        Book book = (discount, price) -> {
            BigDecimal price1 = BigDecimal.valueOf(discount).multiply(price);

            methodPrice.set(price1); 
            return price1;
        };

        book.getPrice(0.8, BigDecimal.valueOf(32.5));

        System.out.println("最终折扣过的价格是:"+ methodPrice);

        // 最终折扣过的价格是:26.00
    }
更改成员变量的值
  static BigDecimal methodPrice = BigDecimal.ZERO;

    public static void main(String[] args) {


        Book book = (discount, price) -> {
            BigDecimal price1 = BigDecimal.valueOf(discount).multiply(price);

            methodPrice = price1;
            return price1;
        };

        book.getPrice(0.8, BigDecimal.valueOf(32.5));

        System.out.println("最终折扣过的价格是:"+ methodPrice);

        // 最终折扣过的价格是:26.00
    }

总结

  1. lambda表达式可以调用并修改类成员变量的值。
  2. lambda表达式只是描述了抽象方法是如何实现的,在抽象方法没有被调用前,lambda表达式中的代码并没有被执行,运行抽象方法之前类成员变量的值不会发生变化。
  3. 只要抽象方法被调用,就会执行lambda表达式中的代码,类成员变量的值就会被修改。

异常处理

编写抽象方法为了保证程序的安全性,会在定义时就抛出异常。lambda表达式中并没有抛出异常的语法,lambda表达式会默认抛出抽象方法原有的异常,当此方法被调用时则需要进行异常处理。
public interface Book {

    boolean getNum(Object num) throws ClassCastException;
}


  public static void main(String[] args) {


        Book book = (num) -> {

            if (!Integer.TYPE.isInstance(num)) {
                throw new ClassCastException("只能接收数字类型");
            }

            number = Integer.parseInt(num.toString());

            return true;
        };

        book.getNum("test");

        // Exception in thread "main" java.lang.ClassCastException: 只能接收数字类型

    }

方法引用

引用静态方法

	lambda 表达式添加了一套新语法,用来引用方法。
	语法: 类名::静态方法名
public interface Book {

    // 定义抽象方法
    int add(int num, int num2);
}



public class Main implements Book {

    public static int number = 0;


    public static void main(String[] args) {
		// 调用静态方法
        Book book = Main::getNumber;
        
        // 直接调用接口返回结果
        int add = book.add(1, 3);

        System.out.println(add);

		// 4

    }
	// 定义静态方法
     static int getNumber(int num, int num2) {
        return num + num2;
    }

    @Override
    public int add(int num, int num2) {
        return 0;
    }
}

引用成员方法

	与调用静态方法不同,引用成员方法 通过对象名来调用方法
	语法: 对象名::成员方法名
public interface Book {

    // 定义抽象方法
    int add(int num, int num2);
}



public class Main implements Book {

    public static int number = 0;


    public static void main(String[] args) {
		// 声明对象
        Main main = new Main();
       // 通过对象来调用方法
        Book book = main::getNumber;

        int add = book.add(1, 3);

        System.out.println(add);

    }

    int getNumber(int num, int num2) {
        return num + num2;
    }

    @Override
    public int add(int num, int num2) {
        return 0;
    }
}

引用带泛型方法

public interface Book<T> {

    // 定义抽象方法
    int add(T[] t);
}

public class Main<T> implements Book<String> {

    public static int number = 0;


    public static void main(String[] args) {

        Main main = new Main();

        String [] str = {"书籍", "报表", "服务"};

        Book book = main::getNum;

        int result =  book.add(str);

        System.out.println(result);

    }

    public int getNum(T[] t) {
        return t.length;
    }

    @Override
    public int add(String[] t) {
        return 0;
    }
}

引用构造方法

lambda 表达式有三种引用构造方法的语法,
	1、无参构造方法
	2、有参构造方法
	3、引用数组构造方法

语法:类名::new
为了区分引用静态方法的语法,使用new关键字,表示引用构造方法。
public interface Book {


    Print add();
}

public class Print implements Book {

    public static void main(String[] args) {

        Book book = Print::new;

        book.add();

        // 无参构造方法

    }


    public Print() {
        System.out.println("无参构造方法");
    }


    public Print(int i) {
        System.out.println("有参构造方法");
    }


    @Override
    public Print add() {
        return null;
    }

}




public class Print implements Book {

    public static void main(String[] args) {

        Book book = Print::new;

        book.add(2);

        // 有参构造方法

    }


    public Print() {
        System.out.println("无参构造方法");
    }


    public Print(int i) {
        System.out.println("有参构造方法");
    }


    @Override
    public Print add(int num) {
        return null;
    }
}

fuction接口

简介

上文实例中,想要使用lambda表达式,必须先创建或者调用已有的函数式接口。
在这里,java.util.funcation包提供了预定义函数式接口。

Function<T, R> 接口

下面介绍常用接口Function<T, R>接口
T: 被操作的类型,类似于方法参数类型
R:操作结果类型,类似于方法的返回类型
方法功能说明方法返回值
apply(T t)抽象方法,按照被子类实现的逻辑,执行函数。参数为被操作泛型对象R
andThen(Function<? super R, ? extends V> after)先执行apply(t)方法,将执行结果作为本方法参数,再按照after函数逻辑继续执行(T t) -> after.apply(apply(t))
compose(Function<? super V, ? extends T> before)先按照before函数逻辑操作接口的被操作对象t,再将执行结果作为apply()方法的参数(V v) -> apply(before.apply(v))
static identity()此方法是静态方法。返回一个Function对象,此对象的apply()方法只会返回参数值t -> t
public class Print {


    // 把数组转为字符串
    Function<String[], String> function = (addressArray) -> {

        StringBuffer address = new StringBuffer();

        for (String str : addressArray) {
            address.append(str);
        }

        return address.toString();
    };

    // 按照回车返回数组
    Function<String, String[]> after = (addressArray) -> addressArray.split("xx");

    // 把每个数组加上回车特殊符号
    Function<String[], String[]> before = (addressArray) -> {

        String[] new_address = new String[addressArray.length];

        for (int i = 0; i < addressArray.length; i++) {
            new_address[i] = addressArray[i]+":";
        }

        return new_address;
    };

    public static void main(String[] args) {

        String[] address = {"xx省", "xx市", "xx区"};

        Print print = new Print();

        String identity = print.getIdentity(address);

        System.out.println(identity);

        // 地址数组长度3

        String apply = print.getApply(print, address);

        System.out.println(apply);
        // xx省xx市xx区

        String compose = print.getCompose(print, address);

        System.out.println(compose);

        // xx省:xx市:xx区:

        String[] strings = compose.split(":");

        String andThen = print.getAndThen(print, strings);

        System.out.println(andThen);

        // 省市区

    }


    private  String getApply(Print print, String[] address) {
        return print.function.apply(address);
    }

    private  String getAndThen(Print print, String[] address) {

        Function<String[], String> function1 = print.function;

        String[] apply = function1.andThen(print.after).apply(address);

        return function1.apply(apply);
    }

    private  String getCompose(Print print, String[] address) {

        Function<String[], String> function1 = print.function;

        return function1.compose(print.before).apply(address);
    }


    private  String getIdentity(String[] address) {
        Function<String, String> identity = Function.identity();
        return identity.apply("地址数组长度" + address.length);
    }
}


流处理

流处理可以对数据进行过滤、映射、查找和收集功能,并且代码量很少。
缺点是 代码可读性不高。

简介

流处理的接口都定义在java.util.stream包下。BaseStream接口是最基础的接口  是stream接口的子接口。
stream接口时泛型接口,可以操作任何类的对象。
类型:
	终端操作,操作会消费流,操作结束之后,被操作的流对象就不能再次执行其他操作了。
	中间操作,会生成一个新的流对象,被操作的流对象任然可以执行其他操作。

在这里插入图片描述

Collection接口新增两个可以获取流对象的方法。可以获取集合的顺序流。
Stream stream();

获取集合的并行流
Stream parallelStream;

Collectors类

Optional类为收集器类,该类实现了java.util.Collector接口,可以将Stream流对象进行各种各样的封装、归集、分组等操作。

在这里插入图片描述

数据过滤

filter()方法
	public class Print {

    public static void main(String[] args) {

        List<String> books = new ArrayList<>();

        books.add("123小说");

        books.add("245名著");

        books.add("书籍");

        Stream<String> stream = books.stream();


        stream = stream.filter(str -> !str.contains("书籍"));

        List<String> list =  stream.collect(Collectors.toList());

        list.forEach(System.out::println);

        // 123小说
        //245名著

    }

}
distinct()过滤方法
可以去除流中的重复元素
    public static void main(String[] args) {

        List<String> books = new ArrayList<>();

        books.add("123小说");

        books.add("123小说");

        books.add("书籍");

        Stream<String> stream = books.stream();

        stream = stream.distinct();

        List<String> list =  stream.collect(Collectors.toList());

        list.forEach(System.out::println);

      //123小说
        //书籍

    }
limit()方法
可以获取流中前N个元素
  public static void main(String[] args) {

        List<String> books = new ArrayList<>();

        books.add("123小说");

        books.add("123小说");

        books.add("书籍");

        Stream<String> stream = books.stream();

        stream = stream.limit(2);

        List<String> list =  stream.collect(Collectors.toList());

        list.forEach(System.out::println);

        //123小说
        //123小说

    }
skip()方法
可以忽略流中的前N个元素
    public static void main(String[] args) {

        List<String> books = new ArrayList<>();

        books.add("123小说");

        books.add("123小说");

        books.add("书籍");

        Stream<String> stream = books.stream();

        stream = stream.skip(1);

        List<String> list =  stream.collect(Collectors.toList());

        list.forEach(System.out::println);

        //123小说
        //书籍

    }

数据映射

数据的映射和过滤概念不同:过滤是在流中找到符合条件的元素,映射是在流中获得具体的数据。
    public static void main(String[] args) {

        List<String> books = new ArrayList<>();

        books.add("123小说");

        books.add("123小说");

        books.add("书籍");

        Stream<String> stream = books.stream();

        stream = stream.filter(s -> s.equals("123小说"));

        List<String> list =  stream.collect(Collectors.toList());

        list.forEach(System.out::println);

        //123小说
        //123小说

    }

数据查找

allMath()方法
判断流中的元素是否全部符合某一条件,返回结果是boolean值。全部元素符合条件true,否则false
    public static void main(String[] args) {

        List<Integer> books = new ArrayList<>();

        books.add(123);

        books.add(2);

        books.add(5);

        Stream<Integer> stream = books.stream();

       Boolean result =  stream.allMatch(integer -> integer>3);

        System.out.println(result);
        // false
    }
anyMatcd()方法
判断流中的元素是否符合某一条件
    public static void main(String[] args) {

        List<Integer> books = new ArrayList<>();

        books.add(123);

        books.add(2);

        books.add(5);

        Stream<Integer> stream = books.stream();

       Boolean result =  stream.anyMatch(integer -> integer>3);

        System.out.println(result);
        // true
    }
findFirst()方法
返回符合条件的第一个元素
 public static void main(String[] args) {

        List<String> books = new ArrayList<>();

        books.add("123");

        books.add("2");

        books.add("444");

        Stream<String> stream = books.stream();

        Stream<String> integerStream = stream.filter(str -> str.contains("2"));

        Optional<String> first = integerStream.findFirst();

        System.out.println(first.get());
        // 123
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值