JDK8-Lambda 表达式

Lambda 表达式

Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。
JDK 也提供了大量的内置函数式接口供我们使用,使得 Lambda 表达式的运用更加方便、高效。

可以对某些匿名内部类的写法进行简化,它是函数式编程思想的一个重要体现,不用关注是什么对象,而是更关注对数据进行了什么操作。

基本格式

(参数列表)->{代码}

范例

范例一:

在创建线程并启动时可以使用匿名内部类的写法;

  • 匿名内部类方式:
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread());
    }
}).start();
  • Lambda方式:
new Thread(() -> {
    System.out.println(Thread.currentThread());
}).start();

范例二:

IntBinaryOperator是一个接口,使用匿名内部类的写法调用该方法;

  • 匿名内部类方式:
public static int calculateNum(IntBinaryOperator operator) {
    int a = 10;
    int b = 20;
    return operator.applyAsInt(a, b);
}

@Test
public void testLambda2() {
    int i = calculateNum(new IntBinaryOperator() {
        @Override
        public int applyAsInt(int left, int right) {
            return left + right;
        }
    });

    System.out.println(i);
}
  • Lambda方式:
public static int calculateNum(IntBinaryOperator operator) {
    int a = 10;
    int b = 20;
    return operator.applyAsInt(a, b);
}

@Test
public void testLambda2() {
    int i = calculateNum((int left, int right) -> {
        return left + right;
    });

    System.out.println(i);
}

范例三:

IntPredicate是一个接口。先使用匿名内部类的写法调用该方法;

  • 匿名内部类方式:
public static void printNum(IntPredicate predicate) {
    int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for (int i : arr) {
        if (predicate.test(i)) {
            System.out.println(i);
        }
    }
}

@Test
public void testLambda3() {
    printNum(new IntPredicate() {
        @Override
        public boolean test(int value) {
            return value % 3 == 0;
        }
    });
}
  • Lambda方式:
public static void printNum(IntPredicate predicate) {
    int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for (int i : arr) {
        if (predicate.test(i)) {
            System.out.println(i);
        }
    }
}

@Test
public void testLambda3() {
    printNum((int value) -> {
        return value % 3 == 0;
    });
}

范例四:

Function是一个接口,先使用匿名内部类的写法调用该方法;

  • 匿名内部类方式:
public static  R typeConver(Function function) {
    String str = "1235";
    R result = function.apply(str);
    return result;
}

@Test
public void testLambda4() {
    Integer result = typeConver(new Function() {
        @Override
        public Integer apply(String s) {
            return Integer.valueOf(s);
        }
    });
    System.out.println(result);
}
  • Lambda方式:
public static  R typeConver(Function function) {
    String str = "1235";
    R result = function.apply(str);
    return result;
}

@Test
public void testLambda4() {
    Integer result = typeConver((String s) -> {
        return Integer.valueOf(s);
    });
    System.out.println(result);
}

范例五:

IntConsumer是一个接口,先使用匿名内部类的写法调用该方法;

  • 匿名内部类方式:
public static void foreachArr(IntConsumer consumer) {
    int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for (int i : arr) {
        consumer.accept(i);
    }
}

@Test
public void testLambda5() {
    foreachArr(new IntConsumer() {
        @Override
        public void accept(int value) {
            System.out.println(value);
        }
    });
  • Lambda方式:
public static void foreachArr(IntConsumer consumer) {
    int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for (int i : arr) {
        consumer.accept(i);
    }
}

@Test
public void testLambda5() {
    foreachArr((int value) -> {
        System.out.println(value);
    });
}

省略规则

  • 参数类型可以省略;
public static void foreachArr(IntConsumer consumer) {
    int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for (int i : arr) {
        consumer.accept(i);
    }
}

@Test
public void testLambda5() {
    foreachArr((value) -> {
        System.out.println(value);
    });
}
  • 方法体只有一句代码时大括号return和唯一一句代码的分号可以省略;
public static void foreachArr(IntConsumer consumer) {
    int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for (int i : arr) {
        consumer.accept(i);
    }
}

@Test
public void testLambda5() {
    foreachArr((value) -> System.out.println(value));
}
  • 方法只有一个参数时小括号可以省略;
public static void foreachArr(IntConsumer consumer) {
    int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for (int i : arr) {
        consumer.accept(i);
    }
}

@Test
public void testLambda5() {
    foreachArr(value -> System.out.println(value));
}
  • 以上这些规则都记不住也可以省略不记,可通过idea的replaceLambda表达式快速生成lambda表达式;

Stream 流

Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作。

Stream – 特性

Stream可以由数组或集合创建,对流的操作分为两种:

  • 中间操作,每次返回一个新的流,可以有多个;
  • 终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。

Stream特性:

  • stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果;
  • stream不会改变数据源,通常情况下会产生一个新的集合或一个值;
  • stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。

JDK8-Lambda 表达式

Stream – 创建方式

Stream创建方式有三种:

  • 通过 java.util.Collection.stream() 方法用集合创建流;
  • 使用java.util.Arrays.stream(T[] array)方法用数组创建流;
  • 使用Stream的静态方法:of()、iterate()、generate()。
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author hos
 * @Createdate 2022/3/21 14:40
 */
public class StreamCreateType {

    public static void main(String[] args) {

        /**
         * Stream 流的创建有3种方式
         *  1. Collection.stream()方法用集合创建
         *  2. Arrays.stream(T[] array) 方法用数组创建
         *  3. 使用Stream的静态方法:of()、iterate()、generate()
         */
        //方式一: Collection.stream()方法用集合创建
        List list = Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9");
        // 创建一个顺序流
        Stream stream = list.stream();
        // 创建一个并行流
        Stream stringStream = list.parallelStream();
        List collect = stringStream.collect(Collectors.toList());

        //方式二: Arrays.stream(T[] array) 方法用数组创建
        int[] array = {1, 2, 3, 4, 5};
        IntStream stream1 = Arrays.stream(array);
        System.out.println(stream1.max().getAsInt());

        //方式三: 使用Stream的静态方法:of()、iterate()、generate()
        Stream intStream = Stream.of(1, 2, 3, 4, 5, 6);
        Stream stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
        // 0 3 6 9
        stream2.forEach(System.out::println);

        AtomicInteger m = new AtomicInteger(10);
        Stream stream3 = Stream.generate(()-> m.getAndIncrement()).limit(3);
        //10 11 12
        stream3.forEach(System.out::println);

        /**
         *  创建流:
         *      - 单列集合: 集合对象.stream()
         *      - 数组: Arrays.stream(数组) 或 Stream.of
         *      - 双列集合: 转换成单列集合后再创建
         */
        //单列集合: 集合对象.stream()
        List listStr = new ArrayList<>();
        Stream stream4 = listStr.stream();

        //数组: Arrays.stream(数组) 或 Stream.of
        Integer[] arr = {1,2,3,4,5};
        Stream stream5 = Arrays.stream(arr);
        Stream stream6 = Stream.of(arr);

        //双列集合: 转换成单列集合后再创建
        Map map = new HashMap<>();
        map.put("hos",19);
        map.put("hosys",17);
        map.put("hosystem",16);
        Stream> stream7 = map.entrySet().stream();
    }
}

Stream – 使用

中间操作

map

map,可以将一个流的元素按照一定的映射规则映射到另一个流中;

map,接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

//Stream - map: 可以将一个流的元素按照一定的映射规则映射到另一个流中
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream创建流
Arrays.stream(arr).map(element -> element + 10).forEach(System.out::println);
filter

filter,对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中;

filter,按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。

//Stream - filter: 对流中的元素进行条件过滤
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream创建流
//打印数组中大于3的元素
Arrays.stream(arr).filter(arrElement -> arrElement > 3).forEach(System.out::println);
distinct

distinct,去除流中的重复元素;

注意: distinct方法是依赖Object的equals方法来判断是否是相同对象的,所以需要注意重写equals方法;

//Stream - distinct: 去除重复元素
Integer[] arr = {1, 2, 2, 3, 3, 4, 4, 5};
//Arrays.stream创建流
//去除重复元素
Arrays.stream(arr).distinct().forEach(System.out::println);
sorted

sorted(),自然排序,流中元素需实现Comparable接口;

sorted(Comparator com),Comparator排序器自定义排序。

注意: 如果调用空参的sorted()方法,需要流中的元素是实现了Comparable。

//Stream - sorted: 自然排序
Integer[] arr = {5,4, 3, 2, 1};
//Arrays.stream创建流
Arrays.stream(arr).sorted().forEach(System.out::println);
limit

limit,可以设置流的最大长度,超出的部分将被抛弃;

//Stream - limit: 设置流的最大长度
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream创建流
Arrays.stream(arr).limit(2).forEach(System.out::println);
skip

skip,跳过流中的前n个元素,返回剩下的元素;

//Stream - skip: 跳过流中的前n个元素
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream创建流
Arrays.stream(arr).skip(2).forEach(System.out::println);
flatMap

flatMap,接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流;

map只能把一个对象转换成另一个对象来作为流中的元素。而flatMap可以把一个对象转换成多个对象作为流中的元素。

//Stream - flatMap: 接收一个函数作为参数,将流中的每个值都换成另一个流
ArrayList list = new ArrayList<>();
ArrayList list1 = new ArrayList<>();
ArrayList list2 = new ArrayList<>();
ArrayList list3 = new ArrayList<>();
ArrayList list4 = new ArrayList<>();
ArrayList list5 = new ArrayList<>();

list1.add("str1");
list2.add("str2");
list3.add("str3");
list4.add("str4");
list5.add("str5");
list.add(list1);
list.add(list2);
list.add(list3);
list.add(list4);
list.add(list5);

list.stream().flatMap(o -> Stream.of(o)).forEach(System.out::println);

终结操作

forEach

forEach方法,通过 lambda 表达式的方式遍历集合中的元素;

forEach,对流中的元素进行遍历操作,通过传入的参数去指定对遍历到的元素进行什么具体操作。

//Stream - forEach: 通过 lambda 表达式的方式遍历集合中的元素
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream创建流
Arrays.stream(arr).forEach(System.out::println);
count

count,用来获取当前流中元素的个数;

//Stream - count: 用来获取当前流中元素的个数
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream创建流
System.out.println(Arrays.stream(arr).count());
max&min

max&min,可以用来或者流中的最值。

//Stream - max&min: 可以用来或者流中的最值
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream创建流
System.out.println(Arrays.stream(arr).max((o1, o2) -> o1 - o2).get());
System.out.println(Arrays.stream(arr).min((o1, o2) -> o1 - o2).get());
collect

collect,把当前流转换成一个集合;

collect,把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合;流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。

//Stream - collect: 把当前流转换成一个集合
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream创建流
//收集大于3且放到list集合中
List collect = Arrays.stream(arr).filter(ele -> ele > 3).collect(Collectors.toList());
System.out.println(collect);
reduce

reduce,把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作;

reduce,对流中的数据按照你指定的计算方式计算出一个结果。

//Stream - reduce: 对流中的数据按照你指定的计算方式计算出一个结果
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream创建流
Integer addSum = Arrays.stream(arr).reduce(1, (result, element) -> result + element);
Integer subSum = Arrays.stream(arr).reduce(1, (result, element) -> result - element);
Integer mulSum = Arrays.stream(arr).reduce(1, (result, element) -> result * element);
Integer divSum = Arrays.stream(arr).reduce(120, (result, element) -> result / element);
System.out.println(addSum);
System.out.println(subSum);
System.out.println(mulSum);
System.out.println(divSum);

Original: https://www.cnblogs.com/HOsystem/p/16084816.html
Author: HOsystem
Title: JDK8-Lambda 表达式

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/606638/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Java对象序列化和反序列化

    Java类的序列化和反序列化 序列化:指将对象转换为字节序列的过程,也就是将对象的信息转换成文件保存。 反序列化:将字节序列转换成目标对象的过程,也就是读取文件,并转换为对象。 几…

    Linux 2023年6月14日
    0106
  • tcpreplay重放报文,tcpdump能抓到包,应用程序收不到包

    现象: 生产环境中有两台服务器A、B,A服务器实时有报文发往B服务器。为了在测试环境测试新功能,故在现网A服务器上tcpdump抓取发往B服务器的报文,然后在测试环境tcprewr…

    Linux 2023年5月27日
    0159
  • Linux磁盘管理

    对Linux来说一切皆文件,Linux归根结底只有一个根目录,一个独立且唯一的文件结构,Linux的每个分区都是用来组成整个文件系统的一部分。所以Linux采用了磁盘挂载的方式,将…

    Linux 2023年6月8日
    0114
  • 大数据集群服务启停脚本/常用端口/时间同步

    1、整体启动/停止HDFS start-dfs.sh/stop-dfs.sh 2、整体启动/停止YARN start-yarn.sh/stop-yarn.sh 1、分别启动/停止H…

    Linux 2023年6月8日
    094
  • centos系统和Ubuntu系统命令区别以及常见操作

    一.前言 二.系统环境 三.命令区别 3.1 使用习惯和命令区别 3.2 服务管理的区别 3.3 软件包信息区别 四.Ubuntu系统常见操作 4.1 Ubuntu系统apt和ap…

    Linux 2023年6月7日
    0231
  • Kafka部署安装及简单使用

    一、环境准备 1、jdk 8+ 2、zookeeper 3、kafka 说明:在kafka较新版本中已经集成了zookeeper,所以不用单独安装zookeeper,只需要在kaf…

    Linux 2023年6月13日
    0118
  • jenkins 设置钉钉机器人+jenkins调用shell脚本使用钉钉机器人自定义发消息并通知指定人

    两种钉钉通知方式,一种是使用安装的钉钉插件来通知,但是这个不好定义通知内容,没办法控制发送条件,只要配置了,不管构建参数(分支,渠道,配置),都会发通知,第二种是使用脚本的方式来通…

    Linux 2023年5月28日
    093
  • 软件工程 软件需求与软件需求规约 第1篇随笔

    2、软件需求与软件需求规约 1. 何为需求? 定义问题的基本要素是 “需求” 一个需求是一个有关”要予构造”的陈述,用以描述待开发产…

    Linux 2023年6月7日
    0103
  • 阿里云-docker上安装redis

    1、取最新版的 Redis 镜像 这里我们拉取官方的最新版本的镜像: $ docker pull redis:latest 2、查看本地镜像 使用以下命令来查看是否已安装了 red…

    Linux 2023年5月28日
    085
  • Error: Unable to access jarfile 运行jar包报错

    1、可能是执行路径有误 错误 修改后,需使用绝对路径 2、决解1后,还报以下错误,就是你的安装的JDK与jar包中的JDK不是同一版本。idea中有自带的JDK与我们安装的JDK版…

    Linux 2023年6月14日
    0938
  • WOE编码与IV值

    参考:WOE与IV值浅谈机器学习-变量筛选之IV值和WOE 0. Introduction WOE (weight of evidence): 证据权重IV (informatio…

    Linux 2023年6月13日
    0157
  • 【Python | opencv+PIL】常见操作(创建、添加帧、绘图、读取等)的效率对比及其优化

    本人准备用python做图像和视频编辑的操作,却发现opencv和PIL的效率并不是很理想,并且同样的需求有多种不同的写法并有着不同的效率。见全网并无较完整的效率对比文档,遂决定自…

    Linux 2023年6月13日
    096
  • [20220302]oracle如何定位使用library cache mutex 2.txt

    [20220302]oracle如何定位使用library cache mutex 2.txt –//这个问题实际上困扰我很久,我开始以为library cache b…

    Linux 2023年6月13日
    083
  • Redis监控技巧(转)

    来自:http://blog.nosqlfan.com/html/4166.html Redis 监控最直接的方法当然就是使用系统提供的 info 命令来做了,你只需要执行下面一条…

    Linux 2023年5月28日
    0100
  • 常用命令-lsof

    作者:Outsrkem原文链接:https://www.cnblogs.com/outsrkem/p/14608224.html本文版权归作者所有,欢迎转载,但未经作者同意必须保留…

    Linux 2023年6月6日
    0105
  • ArchLinux安装-2022-01-12

    这篇教程,是我基于B站up住theCW的视频教程整理的,其中添加了一些我在安装n次之后的经验(虽然失败过几次,但我现在安装不会再出差错,所以请放心的看此教程) 当然,我认为theC…

    Linux 2023年5月27日
    093
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球