Lambda表达式

概述

百度百科的定义:

Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。

  1. JDK8开始支持Lambda表达式,用来让程序编写更优雅
  2. 利用Lambda可以更简洁的实现匿名内部类函数声明与调用
  3. 基于Lambda提供stream流式处理极大简化对集合的操作

1.Lambda表达式 的 语法

在这里插入图片描述
在这里插入图片描述
示例:

/**
 * 四则运算接口
 */
//注解:通知编译器这是函数式接口,进行 抽象方法的检查(只能有一个抽象方法)
@FunctionalInterface
public interface MathOperation {
    public Float operate(Integer a,Integer b);
    //用lambda表达式只能实现函数式接口(接口有且只有一个方法)
}

三种使用Lambda表达式实现函数式接口的方法

public class LambdaSample{
    public static void main(String[] args) {
        //1.标准使用方式
        MathOperation addition = (Integer a,Integer b)->{
            System.out.print("a+b=");
            return a+b+0f;
        };
        System.out.println(addition.operate(2,3));
        //2.允许忽略参数类型
        MathOperation sub = (a,b)->{
            System.out.print("a-b=");
            return a-b+0f;
        };
        System.out.println(sub.operate(2,3));
        //3.单行实现代码可以省略大括号和return
        MathOperation multiplication = (a,b)->a*b+0f;
        System.out.println("a*b="+multiplication.operate(2,3));
    }
}

2.函数式编程

什么是函数式编程
  1. 函数式编程是基于函数式接口并使用lambda表达的编程方式
  2. 函数式编程理念是将代码作为可重用数据代入到程序运行中
  3. 函数式编程强调"你想做什么",而不是"你想怎么做"
什么是函数式接口
  1. 函数式接口是有且只有一个抽象方法的接口
  2. Java中拥有大量函数式接口,如java.lang.Runnable
  3. JDK8后提供了一系列新的函数式接口,位于java.util.function

函数式接口 Predicate 示例:
在这里插入图片描述

public class PredicateSample {
    public static void main(String[] args) {
        Predicate<Integer> predicate = n->n>4; //接受的参数是n ;return的是 n>4
        boolean result = predicate.test(4);
        System.out.println(result); //false

        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
        filter(list,n->n%2==1); //选出奇数
        System.out.println("");
        filter(list,n->n%2==0);//选出所有偶数
        System.out.println("");
        filter(list,n->n>5&&n%2==1);//选出 大于5 的奇数
        //代码作为可重用的资源放入代码中
        //依托函数式接口,将程序的代码作为判断的条件,运行时动态的带入程序,更加灵活
    }
    public static void filter(List<Integer> list,Predicate<Integer> predicate){
    //过滤器,第二个参数接收一个 lambda表达式(自己将结果输出,没有保存)
        for(Integer num:list){
            if(predicate.test(num)){
                System.out.print(num+" ");
            }
        }
    };
}

依托函数式接口,将程序的代码作为判断的条件,运行时动态的带入程序,更加灵活
比如上面这个例子中的filter函数接受的参数 Predicate predicate
他是一个函数式接口,我们传入了一个 lambda表达式 n->n%2==1
函数式接口接受了我们的 lambda表达式,在调用自己的test()方法就能按我们的要求进行筛选了。

3.函数式编程与面向对象编程的比较

在这里插入图片描述

4.常见函数式接口的使用

在这里插入图片描述

Consumer

该接口只有一个 accept() 方法
适用于只需要接受一个参数且不需要任何返回的场景

/**
 * Consumer 接口的使用
 * 适用于只需要接受一个参数且不需要任何返回的场景
 * 只有一个方法accept
 */
public class ConsumerSample {

    public static void main(String[] args) {
        output(s-> System .out.println("控制台打印:"+s));
        output(s->{
            System.out.println("向present网站发送数据包"+s);
        });
    }

    public static void output(Consumer<String> consumer) {
        String text = "一鼓作气,再而衰,三而竭。";
        consumer.accept(text);
    }
}
/**
控制台打印:一鼓作气,再而衰,三而竭。
向present网站发送数据包一鼓作气,再而衰,三而竭。
*/

这个例子中,output() 方法接受一个Consumer类型的函数式接口,
我们传入一个 lambda表达式的同时对这个函数式接口进行了实现,
output() 函数又调用了 Consumer接口的 accept() 方法。

Function

Function函数式接口适用于有一个输入参数需要返回数据的功能代码
只有一个 apply() 方法。

/**
 * 使用Function函数式接口生成随机定长字符串
 */
public class FunctionSample {
    public static void main(String[] args) {
        //第一个参数是接受的参数类型,第二个参数是返回的参数类型
        Function<Integer,String> randomStringFunction = l->{
          String chars = "qwertyuiopasdfghjklzxcvbnm1234567890";
          StringBuffer stringBuffer = new StringBuffer();
            Random random = new Random();
            for(int i=0;i<l;i++){
                int positon = random.nextInt(chars.length());
                stringBuffer.append(chars.charAt(positon));
            }
            return stringBuffer.toString();
        };

        String result = randomStringFunction.apply(16);//生成16位的一个字符串
        System.out.println(result);
    }
}

首先,通过这个例子我们可以学到 生成指定长度的随机字符串的方法。
在这个例子中,我们先声明了一个 Function接口类型的变量(需要用泛型指明接受的参数类型和返回的参数类型)randomStringFunction ,然后使用 lambda表达式 对这个函数式接口进行了实现,
最后我们调用 randomStringFunction 的 apply() 方法 传入参数 l (想要的长度)就能得到返回值 stringBuffer.toString() (定长字符串)

Predicate

用于条件判断,接受一个参数,固定返回 bool 值
只有一个方法 test()
例子见前面那一个

5.Stream流式处理

  1. Stream流式处理是建立在Lambda基础上多数据处理技术
  2. Stream对集合数据处理进行高度抽象,极大简化代码
  3. Stream可对集合进行迭代,去重,筛选,排序,聚合等一系列处理
    在这里插入图片描述
Stream流的五种创建方式
/**
 * Stream 流对象 的五种创建方式
 * 常用的 是基于数组和集合
 * 后三种方法简单了解
 */
public class StreamGenerator {
    //基于数组创建
    @Test
    public void generator(){
        String[] arr = {"Lily","Lucy","Zhang","Mike"};
        Stream<String> stream = Stream.of(arr);//创建流对象(下面再使用流对象的方法简化开发)
        stream.forEach(s-> System.out.println(s)); //forEach 中使用lambda表达式
    }
    //基于集合创建
    @Test
    public void generator2(){
        List<String> list =new ArrayList<>();
        list.add("LiLy");
        list.add("Mike");
        Stream<String> stream = list.stream();
        stream.forEach(s-> System.out.println(s));
    }
    //基于generator方法创建无限长度数据流
    @Test
    public void generator3(){ //为甚么产生了无限长度的数据流
        Stream<Integer> stream = Stream.generate(()->new Random().nextInt(100000)); //长生的数据不超过100000
        stream.limit(10)
                .forEach(i-> System.out.println(i));
    }
    //4.基于迭代器创建流
    @Test
    public void generator4(){
        Stream<Integer> stream = Stream.iterate(2,n->n+2); //从1开始 步长为1
        stream.limit(10).forEach(i-> System.out.println(i)); //limit限制产生的个数
    }
    //5.基于字符序列创建流
    @Test
    public void generator5(){
        String str = "Aa_good_boy_中文";
        IntStream stream = str.chars(); //存着每个字符的 ascall 码(汉字显示Unicode编码)
        stream.forEach(c-> System.out.println((char) c));
    }
}
Stream的常用方法

在这里插入图片描述
常用方法示例:

public class StreamMethod {
    //1.提取集合中所有偶数并求和
    @Test
    public void case1(){
        List<String> list  = Arrays.asList("1","2","3","4","5");
        int sum = list.stream() //获取stream对象
                .mapToInt(s->Integer.parseInt(s)) //将流中的每一个元素转换为整数
                .filter(n->n%2==0)  //对流中的数据进行过滤,满足条件的保留
                .sum(); //求和
        System.out.println(sum);
    }

    //2.所有名字首字母大写
    @Test
    public void case2(){
        List<String> list = Arrays.asList("lili","lucy","mike");
        List<String> nameList = list.stream()
                .map(s->s.substring(0,1).toUpperCase()+s.substring(1))
                //.forEach(s-> System.out.println(s)); //直接遍历流
                .collect(Collectors.toList()); //将流中的数据转换为一个新的List集合
        System.out.println(nameList);
    }

    //3.将所有奇数从大到小进行排序,切不出现重复
    @Test
    public void case3(){
        List<Integer> list = Arrays.asList(1,1,3,6,6,4,3,9,5,5);
        List resultList = list.stream()
                .distinct() //去重
                .filter(n->n%2==1)
                .sorted((a,b)->b-a) //从大到小
                .collect(Collectors.toList()); //将流中的数据转换为一个新的List集合
        System.out.println(resultList);
    }
}

注意这一句:.collect(Collectors.toList()); //将流中的数据转换为一个新的List集合
这样我们对原来的对象进行处理后就可以得到一个新的对象,然后就可以声明一个变量来接收这个新的对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值