JAVA8 lambda表达式权威教程

Java 8新特性----Stream流

jdk8是Java 语言开发的一个主要版本,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等等。今天就重点介绍一个非常重要得特性之一 lambda表达式

一:什么是 Stream?

Stream(流)是一个来自数据源的元素队列并支持聚合操作

Java中的Stream并不会存储元素,而是按需计算。 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。

聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。 和以前的Collection操作不同,Stream操作还有两个基础的特征如下:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格。 这样做可以对操作进行优化, 比如延迟执行和短路。
  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫>做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

二:Stream API 使用

1:使用Stream步骤:

(1)先产生一个流(Stream)一个数据源,获取一个流。

(2)中间链式操作 一个中间的操作链,对数据源的数据进行处理。

(3)产生一个新流:一个终止操作,执行中间操作,产生结果。

注意:Stream操作是延迟执行,他们会等需要结果的时候才会执行。

总结:

  • 中间操作常用方法有:筛选:filter 映射:map 排序:sorted提取与组合 收集:collect。
  • 终止操作:遍历:foreach 匹配:find、match 规约:reduce 聚合:max、min、count。

2:创建Stream的方法的4种方式

【1】Collection接口中的方法:
        default Stream<E> stream()  获取串行流
        default Stream<E> parallelStream() 获取并行流
      案例:
//方式1:Collection接口的方法
Collection collection = new ArrayList();
Stream stream = collection.stream();
Stream stream1 = collection.parallelStream();

//方式2:通过Arrays中的Stream方法  数组
IntStream stream2 = Arrays.stream(new int[]{1, 2, 3, 4, 5});

//方式3:Stream中的of方法
Stream<String> stream3 = Stream.of("111", "222", "333");

//方法4:Stream中的方法  创建无限流  (结果是无线个)
Stream<Integer> iterate = Stream.iterate(2, (x) -> x + 2);

3:中间操作

1:筛选与切片

① Stream filter(Predicate<?super T> predicate)返回由与此给定谓词匹配的此流的元素组成的流。 --->接收Lambda,从流中排除某些元素。

 //1:创建Stream;
  Stream<Student> stream = list.stream();

 //2:filter方法(找到年龄大于等于18岁的学生)
 Stream<Student> studentStream = stream.filter((student) -> student.getAge() >= 18);

  //3:终止操作;如果没有终止操作的话,上面的第二步中间操作不执行
   studentStream.forEach(System.out::println);
   /**
    * 注意:如果值执行1,2操作的话,不会有任何结果。
    * 验证出Steam操作是延迟的,只有进行了终止操作,才会执行中间操作!这就是所谓的延迟加载
*/

②Stream limit(Long maxSize) 返回由该流的元素组成的流,截断长度不能超过maxSize. 只有找到maxSize个满足条件的即可。 ---->截断流,使其元素不超过给定的数量。

 public void limitTest02() {
        //Limit方法 短路(效率增高),只要找到了2个满足条件的,后面的迭代操作就不在执行了!
        list.stream().filter(x -> {
            System.out.println("正在过滤!!");
            return x.getAge() > 18;
        }).limit(2).forEach(System.out::println);
    }

③Stream skip(Long n) 在丢掉流的第一个n元素后,返回由该流的n元素组成的流,如果此流包含少于n元素,那么将返回一个空流。 ---->跳过元素,返回一个扔掉了前n个元素的流。 如果流中的元素不足n个,则返回一个空流,与limit(n)互补。

public void skipTest03() {
     //skip 方法跳过前2个满足条件的  留下后面满足条件的结果!!
     list.stream().filter(x -> {
         System.out.println("正在过滤后面满足条件的结果");
         return x.getAge() > 18;
     }).skip(2).forEach(System.out::println);
 }

④Stream distinct()

注意: 自定义的类在去重的过程中必须重新hashCode和equals方法,因为distinct实现的时候底层去找这两个方法。

 public void distinctTest04() {
   //distinct 去重操作!
       list.stream().distinct().forEach(System.out::println);
   }

⑤ map映射:

如果需要将流中的元素映射到另一个流中,可以使用map方法。方法签名: Stream map(Function<? super T, ? extends R> mapper); 该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。 Stream流中的map方法基本使用的代码如:

@Test
public void testMap() {
    Stream<String> original = Stream.of("11", "22", "33");
    Stream<Integer> result = original.map(Integer::parseInt);
    result.forEach(s -> System.out.println(s + 10));
}
//这段代码中,map方法的参数通过方法引用,将字符串类型转换成为了int类型(并自动装箱为Integer类对象)。

⑥ 排序 (两种方式)

(1)Stream sorted()返回此流元素组成的流,根据自然顺序排序。底层按照内部比较器进行排序,实现Comparable接口中的compareTo方法。

(2)Stream sorted(Comparator<?super T>comparator) 返回由此元素组成的流,根据挺的Comparator进行顺序排序。指定顺序。 指定排序策略:底层按照外部比较器进行排序 Comparator接口一定要重新Compare方法。

基本使用
Stream流中的sorted方法基本使用的代码如:
@Test
public void testSorted() {
    // sorted(): 根据元素的自然顺序排序
    // sorted(Comparator<? super T> comparator): 根据比较器指定的规则排序
    Stream.of(33, 22, 11, 55)
            .sorted()
            .sorted((o1, o2) -> o2 - o1)
            .forEach(System.out::println);
}
这段代码中,sorted方法根据元素的自然顺序排序,也可以指定比较器排序。

4:终止操作

①查找(find)和匹配(match)

如果需要找到某些数据,可以使用find相关方法。方法签名:

  • Optional findFirst();
  • Optional findAny();

Stream流中的find相关方法使用代码:

@Test
public void testFind() {
    Optional<Integer> first = Stream.of(5, 3, 6, 1).findFirst();
    System.out.println("first = " + first.get());

    Optional<Integer> any = Stream.of(5, 3, 6, 1).findAny();
    System.out.println("any = " + any.get());
}

Stream流的match方法

如果需要判断数据是否匹配指定的条件,可以使用Match相关方法。方法签名:

  • boolean allMatch(Predicate<? super T> predicate);
  • boolean anyMatch(Predicate<? super T> predicate);
  • boolean noneMatch(Predicate<? super T> predicate);

基本使用 Stream流中的Match相关方法使用代码如:

@Test
public void testMatch() {
    boolean b = Stream.of(5, 3, 6, 1)
            // .allMatch(e -> e > 0); // allMatch: 元素是否全部满足条件
            // .anyMatch(e -> e > 5); // anyMatch: 元素是否任意有一个满足条件
            .noneMatch(e -> e < 0); // noneMatch: 元素是否全部不满足条件
    System.out.println("b = " + b);
}    

②:遍历 foreach

//forEach 用来遍历流中的数据
 @Test
    public void test02() {
        //案例1、2下面两种写法等同
        list.stream().map((x)->x.getName()).forEach(System.out::println);
        list.stream().map(Student::getName).forEach(System.out::println);
    }

③Stream流的max、min

List<String> list13 = Arrays.asList("zhangsan","lisi","wangwu","xuwujing");
 int maxLines = list13.stream().mapToInt(String::length).max().getAsInt();
 int minLines = list13.stream().mapToInt(String::length).min().getAsInt();
 System.out.println("最长字符的长度:" + maxLines+",最短字符的长度:"+minLines);
 //最长字符的长度:8,最短字符的长度:4

④Stream流的count

 // Stream流提供count方法来统计其中的元素个数:long count();
  //该方法返回一个long值代表元素个数。基本使用:
@Test
public void testCount() {
   List<String> strList = new ArrayList<>();
   Collections.addAll(strList, "张无忌", "周芷若", "赵敏", "小昭", "杨不悔);
   System.out.println(strList.stream().count());
}

⑤ 分组:groupingBy;

当我们使用Stream流处理数据后,可以根据某个属性将数据分组:

// 案例:
    @Test
    public void testGroup() {
        Stream<Student> studentStream = Stream.of(
                new Student("赵丽颖", 52, 95),
                new Student("杨颖", 56, 88),
                new Student("迪丽热巴", 56, 55),
                new Student("柳岩", 52, 33));
        // Map<Integer, List<Student>> map = studentStream.collect(Collectors.groupingBy(Student::getAge));
        // 将分数大于60的分为一组,小于60分成另一组
        Map<String, List<Student>> map = studentStream.collect(Collectors.groupingBy((s) -> {
            if (s.getSocre() > 60) {
                return "及格";
            } else {
                return "不及格";
            }
        }));
        map.forEach((k, v) -> {
            System.out.println(k + "::" + v);
        });
    }
效果:
不及格::[Student{name='迪丽热巴', age=56, socre=55}, Student{name='柳岩', age=52, socre=33}]
及格::[Student{name='赵丽颖', age=52, socre=95}, Student{name='杨颖', age=56, socre=88}]

⑥拼接:joining

Collectors.joining会根据指定的连接符,将所有元素连接成一个字符串。
// 拼接
@Test
public void testJoining() {
    Stream<Student> studentStream = Stream.of(
            new Student("赵丽颖", 52, 95),
            new Student("杨颖", 56, 88),
            new Student("迪丽热巴", 56, 99),
            new Student("柳岩", 52, 77));
    String collect = studentStream
            .map(Student::getName)
            .collect(Collectors.joining(">_<", "^_^", "^v^"));
    System.out.println(collect);
}

效果:

^_^赵丽颖>_<杨颖>_<迪丽热巴>_<柳岩^v^

⑦聚合:toList,toSet,toMap;

Stream流提供collect方法,其参数需要一个java.util.stream.Collector<T,A, R>接口对象来指定收集到哪种集合中。

  • public static Collector<T, ?, List> toList():转换为List集合。
  • public static Collector<T, ?, Set> toSet():转换为Set集合。
  • public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper):转换为Map集合。

下面是这两个方法的基本使用代码:

// 将流中数据收集到集合中
@Test
public void testStreamToCollection() {
    Stream<String> stream = Stream.of("aa", "bb", "cc");
    // List<String> strList = stream.collect(Collectors.toList());
    // Set<String>  strSet = stream.collect(Collectors.toSet());

    ArrayList<String> arrayList = stream.collect(Collectors.toCollection(ArrayList::new));
    HashSet<String> hashSet = stream.collect(Collectors.toCollection(HashSet::new));
}

toMap

@Test
    public void testCollectToMap(){
        //案例1
        List<Integer> list = Arrays.asList(1, 2, 3);
        Map<String, String> collect1 = list.stream().map(i -> i).collect(Collectors.toMap(key -> "key" + key, value -> "value:" + value));

        //实体list转化map id作为主键,对象作为value
        List<User> userList =new ArrayList<User>();
        UserTask userTask = new UserTask();
        userTask.setId(1);
        userTask.setName("测试");
        userList.add(userTask);

        Map<Integer,UserTask> taskMap = userList.stream().collect(Collectors.toMap(UserTask::getId, entity -> entity));
        System.out.println(collect1.toString());
        System.out.println(taskMap.toString());
    }

以上就是JAVA8 lambda表达式权威教程!的详细内容,更多关于JAVA8 lambda表达式的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java8新特性lambda表达式有什么用(用法实例)

    我们期待了很久lambda为java带来闭包的概念,但是如果我们不在集合中使用它的话,就损失了很大价值.现有接口迁移成为lambda风格的问题已经通过default methods解决了,在这篇文章将深入解析Java集合里面的批量数据操作(bulk operation),解开lambda最强作用的神秘面纱. 1.关于JSR335 JSR是Java Specification Requests的缩写,意思是Java 规范请求,Java 8 版本的主要改进是 Lambda 项目(JSR 335),其

  • Java8新特性Lambda表达式的一些复杂用法总结

    简介 lambda表达式是JAVA8中提供的一种新的特性,它支持Java也能进行简单的"函数式编程". 它是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数. 本文将介绍关于Java8 Lambda表达式的一些复杂用法,分享出来供大家参考学习,下面来一起看看详细的介绍: 复杂用法实例 传入数组ids,在list<Obj>上操作,找出Obj中id想匹配的,并且按

  • Java8深入学习系列(一)lambda表达式介绍

    前言 最近在学习java8,所以接下来会给大家介绍一系列的Java8学习内容,那么让我们先从lambda表达式开始. 众所周知从java8出现以来lambda是最重要的特性之一,它可以让我们用简洁流畅的代码完成一个功能. 很长一段时间java被吐槽是冗余和缺乏函数式编程能力的语言,随着函数式编程的流行java8种也引入了 这种编程风格.在此之前我们都在写匿名内部类干这些事,但有时候这不是好的做法,本文中将介绍和使用lambda, 带你体验函数式编程的魔力. 什么是lambda? lambda表达

  • Java8新特性之Lambda表达式浅析

    说到java 8,首先会想到lambda(闭包)以及虚拟扩展方法(default method),这个特性早已经被各大技术网站炒得沸沸扬扬了,也是我们java 8系列开篇要讲的第一特性(JEP126 http://openjdk.java.net/jeps/126),jdk8的一些库已经应用了lambda表达式重新设计了,理解他对学习java 8新特性有着重要的意义. 一.函数式接口 函数式接口(functional interface 也叫功能性接口,其实是同一个东西).简单来说,函数式接口是

  • Java8中lambda表达式的应用及一些泛型相关知识

    语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利 顺带用到一些泛型编程,一切都是为了简化代码 场景: 一个数据类,用于记录职工信息 public class Employee { public String name; public int age; public char sex; public String time; public int salary; } 我们有一列此类数据 List<Employee> data = Arrays.asL

  • JAVA8 lambda表达式权威教程

    Java 8新特性----Stream流 jdk8是Java 语言开发的一个主要版本,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等等.今天就重点介绍一个非常重要得特性之一 lambda表达式 一:什么是 Stream? Stream(流)是一个来自数据源的元素队列并支持聚合操作 Java中的Stream并不会存储元素,而是按需计算. 数据源 流的来源. 可以是集合,数组,I/O channel, 产生器generator 等. 聚合操作 类似

  • Java8中的lambda表达式入门教程

    1.基本介绍 lambda表达式,即带有参数的表达式,为了更清晰地理解lambda表达式,先上代码: 1.1 两种方式的对比 1.1.1 方式1-匿名内部类 class Student{ private String name; private Double score; public Student(String name, Double score) { this.name = name; this.score = score; } public String getName() { ret

  • Java8 lambda表达式2种常用方法代码解析

    与python不一样,python lambda是定义匿名函数,而在java8中lambda是匿名内部类 例1.用lambda表达式实现Runnable 我开始使用Java 8时,首先做的就是使用lambda表达式替换匿名类,而实现Runnable接口是匿名类的最好示例.看一下Java 8之前的runnable实现方法,需要4行代码,而使用lambda表达式只需要一行代码.我们在这里做了什么呢?那就是用() -> {}代码块替代了整个匿名类. // Java 8之前: new Thread(ne

  • Java8 lambda表达式的10个实例讲解

    目录 例1.用lambda表达式实现Runnable 例2.使用Java 8 lambda表达式进行事件处理 例3.使用lambda表达式对列表进行迭代 例4.使用lambda表达式和函数式接口Predicate 例5.如何在lambda表达式中加入Predicate 例6.Java 8中使用lambda表达式的Map和Reduce示例 例7.通过过滤创建一个String列表 例8.对列表的每个元素应用函数 例9.复制不同的值,创建一个子列表 例10.计算集合元素的最大值.最小值.总和以及平均值

  • Java8 Lambda表达式详解及实例

    第一个Lambda表达式 在Lambda出现之前,如果我们需要写一个多线程可能需要下面这种方式: Runnable runnable = new Runnable() { @Override public void run() { System.out.println("Hello runnable"); } }; ... thread.start(); 上面的例子如果改成使用Lambda就会简单许多: Runnable noArgs = ()->System.out.print

  • Java8 Lambda表达式模板方法实现解析

    Java注解提供了关于代码的一些信息,但并不直接作用于它所注解的代码内容.在这个教程当中,我们将学习Java的注解,如何定制注解,注解的使用以及如何通过反射解析注解. Java1.5引入了注解,当前许多java框架中大量使用注解,如Hibernate.Jersey.Spring.注解作为程序的元数据嵌入到程序当中.注解可以被一些解析工具或者是编译工具进行解析.我们也可以声明注解在编译过程或执行时产生作用. 在使用注解之前,程序源数据只是通过java注释和javadoc,但是注解提供的功能要远远超

  • java8 forEach结合Lambda表达式遍历 List操作

    我就废话不多说了,大家还是直接看代码吧~ @Test void testJava8ForeachMap() { Map<String, Integer> items = new HashMap<>(); items.put("A", 10); items.put("B", 20); items.put("C", 30); items.put("D", 40); items.put("E&quo

  • Java8新特性:Lambda表达式之方法引用详解

    1.方法引用简述 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法.方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文.计算时,方法引用会创建函数式接口的一个实例. 当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些.方法引用是一种更简洁易懂的Lambda表达式. Lambda表达式全文详情地址:http://blog.csdn.net/sun_promise/article/details/

  • 详解Java8中的lambda表达式、::符号和Optional类

    Java8中的lambda表达式.::符号和Optional类 0. 函数式编程 函数式编程(Functional Programming)属于编程范式(Programming Paradigm)中的用语,此外还有命令式编程(Imperative Programing)等,有兴趣的同学可以自行了解,我们这里大概解释一下函数式编程,在函数式编程中,输入一旦确定了,输出都确定了,函数调用的结果只依赖于传入的输入变量和内部逻辑,不依赖于外部,这样的写出的函数没有副作用.举个例子: public cla

随机推荐