stream流及lambda表达式快速总结

前言:


内容:

stream流是对集合迭代器的增强,使得对集合可以进行高效的聚合操作(过滤,排序、统计分组)或者大批量数据操作,stream流中用到了lambda表达式进行高效率代码书写。lambda可以用来代替匿名函数,使得代码更为简洁。
stream流可分为stream串行流(默认)和parallelStream并行流。一般来说,并行流是不安全的,需要加同步锁;并行流一般适用于CPU使用较多的环境下的通信,因此一些I/O操作频繁的情况不适用并行流。
stream流应用大体流程
1) 把集合转换成流stream
2) 在管道里对流进行中间操作
3) 得到最后的结果,并将流转成集合

lambda表达式的使用条件有
1) 接口中只有一个未被实现
2) 有默认实现的方法除外(default)
3) Object类对应的方法除外
综上,lambda是基于函数式接口编程。

1、与lambda相识

lambda表达式(参数)->{表达式};其中参数可以带数据类型,表达式只有一条可以舍弃大括号,同理参数若有多个便不能舍弃括号。为了方便理解下面是一个打卡的简单例子

/**
 * @Auther:刘兰斌
 * @Date: 2021/05/30/10:40
 * @Explain:
 */
public class test116 {
    //打卡
    interface Sign{
        void sign(String people);
    }
    //员工打卡
    public void signway(String people,Sign si){
        si.sign(people);
    }

    public static void main(String[] args) {
        test116  tes6 = new test116();
        String people ="小刚";
        //法一:用lambda表达式
        tes6.signway(people,p -> System.out.println(p));
        //法二:用匿名内部类
//        Sign s = new Sign() {
//            @Override
//            public void sign(String people) {
//                System.out.println(people);
//            }
//        };
//        tes6.signway(people,s);
    }
}

再来一个案例,下面
在这个吃苹果的案例中,lambda表达式部分相当于使用方法的引用去实现,将表达式中的逻辑方法传入到eat方法中,随后对其进行相同逻辑操作。

public class LambdaTest {

    @Test
    public void test() {
        eat((a,b)-> a+b);
    }

    public static void eat(myinterface mface) {
        System.out.println(mface.eatApple("小飞", 1));
    }
    @FunctionalInterface
    interface myinterface {
        String eatApple(String name, int number);
    }
}

2、初识stream
例a

public static void main(String[] args) {
        List<String> names = Arrays.asList("Tommi", "Davy", "Philipp", "Henry", "Roy", "Jack", "Jerry");
        List<String> res = names.stream()
                .filter(e -> e.startsWith("J"))
                .map(String::toLowerCase)
                .sorted()
                .collect(Collectors.toList());
        System.out.println(res);
    }

结果:[jack, jerry]
解析:上面例子中集合转成流后,filter()中存放着过滤规则,可以用lambda表达式或者谓词逻辑;map()存放着对每个元素的数据转换规则,包括自定义的函数或者系统自带的函数;sorted()存放着排序规则,默认升序排列,最后将流再转成集合。若数据的存储方式为数组,那么转换方式为:int[] a= {2,4,5,6}; Stream.of(a)…

    public static void main(String[] args) {
        String[] str = {"Tommi", "Davy", "Philipp", "Henry", "Roy", "Jack", "Jerry"};
        Stream.of(str)
        .mapToInt(s -> s.length())//等价于.mapToInt(String::length)
        .forEach(System.out::println);
    }
}

同样的,集合类中的set、map都可以转换。
如果是文本文件则用Files.lines获取:如下

public static void main(String[] args) {
        //文本转成流操作
        try {
            Stream<String> stream6 = Files.lines(Paths.get("src/main/resources/test116.txt"));
            List<String> res = stream6.filter(s -> s.equals("Haha"))
                    .map(String::toUpperCase)
                    .collect(Collectors.toList());
            System.out.println(res);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

例b
在filter()中使用谓词逻辑,可以增加程序的复用性。当然可以直接在filter中写lambda表达式,如下面例子中的filter可以写成
filter(s->s.getAge>60 && s.getGender().euquals(“F”))

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @Auther:刘兰斌
 * @Date: 2021/05/30/12:01
 * @Explain:为了方便描述,将对象与测试方法写在一起
 * 需求:找出年龄超过60的女性职工
 */
public class FilterTest {
    public static void main(String[] args) {
        Staff staff01 = new Staff(1,23,"F","Rick","Beethoven");
        Staff staff02 = new Staff(2,13,"M","Rock","ven");
        Staff staff03 = new Staff(3,73,"M","Re","oven");
        Staff staff04 = new Staff(4,53,"F","james","Bee");
        Staff staff05 = new Staff(5,63,"M","Raty","hove");
        Staff staff06 = new Staff(6,33,"M","dtt","love");
        Staff staff07 = new Staff(7,83,"F","yu","ko");
        Staff staff08 = new Staff(8,103,"M","tu","so");
        Staff staff09 = new Staff(9,113,"F","po","bye");
        Staff staff10 = new Staff(10,123,"M","jo","all");
        List<Staff> staffs = Arrays.asList(staff01, staff02, staff03, staff04, staff05, staff06, staff07, staff08, staff09, staff10);
        List<Staff> res = staffs.stream()
                .filter(Staff.ageOver60.and(Staff.genderIsF))//这里.and代表并,表达或用.or,表达否定用negate()
                .collect(Collectors.toList());
        System.out.println(res);
    }
}
@Data
@AllArgsConstructor
class Staff{
    private int id;
    private int age;
    private String gender;
    private String firstname;
    private String lastname;
    //声明谓语,方便复用
    public static Predicate<Staff> ageOver60 = a -> a.getAge()>60;
    public static Predicate<Staff> genderIsF = g -> g.getGender().equals("F");
}

例c
map()进行数据类型转换,有返回值,可以用peek()替换map(),此无返回值

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


/**
 * @Auther:刘兰斌
 * @Date: 2021/05/30/12:41
 * @Explain:
 * 需求:
 *      将所有员工的年龄加1,并且性别改为全称,如F->female;M->male
 */
public class MapTest {
    public static void main(String[] args) {
        Staffn staff01 = new Staffn(1,23,"F","Rick","Beethoven");
        Staffn staff02 = new Staffn(2,13,"M","Rock","ven");
        Staffn staff03 = new Staffn(3,73,"M","Re","oven");
        Staffn staff04 = new Staffn(4,53,"F","james","Bee");
        Staffn staff05 = new Staffn(5,63,"M","Raty","hove");
        Staffn staff06 = new Staffn(6,33,"M","dtt","love");
        Staffn staff07 = new Staffn(7,83,"F","yu","ko");
        Staffn staff08 = new Staffn(8,103,"M","tu","so");
        Staffn staff09 = new Staffn(9,113,"F","po","bye");
        Staffn staff10 = new Staffn(10,123,"M","jo","all");
        List<Staffn> staffs = Arrays.asList(staff01, staff02, staff03, staff04, staff05, staff06, staff07, staff08, staff09, staff10);
        List<Staffn> res = staffs.stream()
                .map(s -> {
                    s.setAge(s.getAge() + 1);
                    s.setGender(s.getGender().equals("M") ? "male" : "female");
                    return s;
                })
                .collect(Collectors.toList());
        System.out.println(res);

    }
}
@Data
@AllArgsConstructor
class Staffn{
    private int id;
    private int age;
    private String gender;
    private String firstname;
    private String lastname;
}



另外,在进行多维数组的操作时多用flatmap(),具体表现如下
        Stream.of("hello", "flatmap")
                .flatMap(fm -> Arrays.stream(fm.split("")))
                .forEach(System.out::println);

例d
多用户多线程多请求的公共数据等就是状态,filter、map、flatmap就是无状态的,即它能独立的做完手头的东西,另外一些有状态的操作如distinct、limit、skip、sorted等就属于有状态的操作,它需要同其他操作一起进行。

    List<String> res = Stream.of("Tommi", "Davy", "Philipp", "Henry", "Roy", "Jack", "Jerry")
                .limit(2)//.forEach(System.out::println)
                .collect(Collectors.toList());
        System.out.println(res);
        List<String> res2 = Stream.of("Tommi", "Davy", "Philipp", "Henry", "Roy", "Jack", "Jerry")
                .skip(2)
                .collect(Collectors.toList());
        System.out.println(res2);
        List<String> res3 = Stream.of("Tommi", "Davy", "Philipp", "Henry", "Roy", "Jack", "Jerry")
                .sorted()
                .collect(Collectors.toList());
        System.out.println(res3);
        List<String> res4 = Stream.of("Tommi", "Davy", "Philipp", "Henry", "Roy", "Jack", "Jerry", "Tommi", "Davy", "Philipp", "Henry")
                .distinct()
                .collect(Collectors.toList());
        System.out.println(res4);

结果
[Tommi, Davy]
[Philipp, Henry, Roy, Jack, Jerry]
[Davy, Henry, Jack, Jerry, Philipp, Roy, Tommi]
[Tommi, Davy, Philipp, Henry, Roy, Jack, Jerry]


注:并行状态中会导致有状态操作失真。并行模式更适合数组、ArrayList、HashMap等,链表就比较适合串行模式。


例e
sort()

    public static void main(String[] args) {
        //排序方法
        List<Integer> number = Arrays.asList(1, 5, 7, 3, 9, 0, 34, 88);
        //  number.sort(Comparator.naturalOrder());//字母表大小写
        number.sort(Comparator.reverseOrder());//逆序
        System.out.println(number);
        List<String> strings = Arrays.asList("Tommi", "Davy", "Philipp", "Henry", "Roy", "Jack", "Jerry", "dd");
        //strings.sort(Comparator.naturalOrder());//先大写再小写
        strings.sort(String.CASE_INSENSITIVE_ORDER);//按大小写不敏感排序
        System.out.println(strings);
    }
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.function.Predicate;

@Data
@AllArgsConstructor
public class Employee {
    private Integer id;
    private Integer age;
    private String gender;
    private String firstname;
    private String lastname;

    //写上谓词逻辑,为了复用
     public static final Predicate<Employee> ageOver70 = a -> a.getAge()>70;
     public static final Predicate<Employee> genderIsM = g -> g.getGender().equals("M");
}

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Auther:刘兰斌
 * @Date: 2021/05/30/13:34
 * @Explain:
 * 需求:
 *      按年龄倒序输出后,再按年龄倒序输出
 */
public class SortTest {
    public static void main(String[] args) {
//        //传统排序方法
//        List number = Arrays.asList(1, 5, 7, 3, 9, 0, 34, 88);
//        //  number.sort(Comparator.naturalOrder());//字母表大小写
//        number.sort(Comparator.reverseOrder());//逆序
//        System.out.println(number);
//        List strings = Arrays.asList("Tommi", "Davy", "Philipp", "Henry", "Roy", "Jack", "Jerry", "dd");
//        //strings.sort(Comparator.naturalOrder());//先大写再小写
//        strings.sort(String.CASE_INSENSITIVE_ORDER);//按大小写不敏感排序
//        System.out.println(strings);
        Employee e1 = new Employee(1,23,"F","Rick","Beethoven");
        Employee e2 = new Employee(2,13,"M","Rock","ven");
        Employee e3 = new Employee(3,73,"M","Re","oven");
        Employee e4 = new Employee(4,53,"F","james","Bee");
        Employee e5 = new Employee(5,63,"M","Raty","hove");
        Employee e6 = new Employee(6,33,"M","dtt","love");
        Employee e7 = new Employee(7,83,"F","yu","ko");
        Employee e8 = new Employee(8,103,"M","tu","so");
        Employee e9 = new Employee(9,113,"F","po","bye");
        Employee e10 = new Employee(10,123,"M","jo","all");
        List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
        employees.sort(Comparator.comparing(Employee::getGender)
                .thenComparing(Employee::getAge)
                .reversed()
        );
        employees.forEach(System.out::println);

    }
}

可以自定义排序规则

import java.util.Arrays;
import java.util.List;


/**
 * @Auther:刘兰斌
 * @Date: 2021/05/30/13:34
 * @Explain:
 * 需求:
 *      年龄逆序输出
 *
 */
public class SortTest {
    public static void main(String[] args) {
        Employee e1 = new Employee(1,23,"F","Rick","Beethoven");
        Employee e2 = new Employee(2,13,"M","Rock","ven");
        Employee e3 = new Employee(3,73,"M","Re","oven");
        Employee e4 = new Employee(4,53,"F","james","Bee");
        Employee e5 = new Employee(5,63,"M","Raty","hove");
        Employee e6 = new Employee(6,33,"M","dtt","love");
        Employee e7 = new Employee(7,83,"F","yu","ko");
        Employee e8 = new Employee(8,103,"M","tu","so");
        Employee e9 = new Employee(9,113,"F","po","bye");
        Employee e10 = new Employee(10,123,"M","jo","all");
        List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
        employees.sort((p1,p2)->{
            if(p1.getAge() == p2.getAge()){
                return 0;
            }
            return p2.getAge()-p1.getAge();

        });
        employees.forEach(System.out::println);

    }
}

public class TestNewDay {
/*
在这个类中需要先建立一个JavaBean,包含    
private  Integer id;
    private  String color;
    private  Integer weight;
    private  String origin;
生成相应的getter、setter方法
通过终止操作符进行收集,按照颜色分组,再计算组内各个元素的平均值。

*/

    private static List<NewDay> list = new ArrayList<>();
    static{
        list.add(new NewDay(1,"Red",300,"China"));
        list.add(new NewDay(2,"blue",230,"河北"));
        list.add(new NewDay(6,"Red",400,"China"));
        list.add(new NewDay(5,"yellow",730,"河北"));
        list.add(new NewDay(8,"Red",900,"China"));
        list.add(new NewDay(7,"yellow",270,"河北"));
        list.add(new NewDay(3,"Red",350,"China"));
        list.add(new NewDay(11,"blue",232,"河北"));
        }
        @Test
    //统计所有颜色的苹果的平均重量
    public void getAverageWeightByColer(){
        Map<String, Double> collect = list.stream()
                .collect(Collectors.groupingBy(e -> e.getColor(),
                        Collectors.averagingInt(a -> a.getWeight())));
        collect.forEach((k,v)-> System.out.println(k+":"+v));
    }
}


注:lambda表达式只能用于函数式接口
函数式接口特点:

  • 有且只有一个抽象方法
  • 允许定义default非抽象方法,且所有的实现类都不会去重写这个方法。
  • 允许静态非抽象方法

3、匹配规则
以下匹配规则可以是lambda表达式或者谓词
anymatch(“匹配规则”);返回值是布尔类型;
allmatch(“匹配规则”):判读是不是所有的都符合匹配规则
nonematch(“匹配规则”):判读是不是不存在匹配规则的数据

optional类型来说明所要找的数据是否存在,存在则用get()取出,否则抛出异常
isPresent():查找的值是否存在,返回值是布尔类型
findall()、findany()

import java.util.Arrays;
import java.util.List;
import java.util.Optional;


/**
 * @Auther:刘兰斌
 * @Date: 2021/05/30/13:34
 * @Explain:

 *
 */
public class SortTest {
    public static void main(String[] args) {
        Employee e1 = new Employee(1,23,"F","Rick","Beethoven");
        Employee e2 = new Employee(2,13,"M","Rock","ven");
        Employee e3 = new Employee(3,73,"M","Re","oven");
        Employee e4 = new Employee(4,53,"F","james","Bee");
        Employee e5 = new Employee(5,63,"M","Raty","hove");
        Employee e6 = new Employee(6,33,"M","dtt","love");
        Employee e7 = new Employee(7,83,"F","yu","ko");
        Employee e8 = new Employee(8,103,"M","tu","so");
        Employee e9 = new Employee(9,113,"F","po","bye");
        Employee e10 = new Employee(10,123,"M","jo","all");
        List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
        boolean b = employees.stream()
                .anyMatch(e -> e.getAge() > 100);
        System.out.println(b);
        boolean b1 = employees.stream().allMatch(Employee.ageOver70);
        System.out.println(b1);
        boolean b2 = employees.stream().noneMatch(c -> c.getAge() > 300);
        System.out.println(b2);
        employees.stream()
                .filter(e -> e.getAge() == 33)
                .findAny()//.findFirst()
                .orElse(new Employee(0,0,"F","",""));//.ifPresent(s-> System.out.println(s));  .isPresent();
    }
}

4、规约

import java.util.Arrays;
import java.util.List;
import java.util.Optional;


/**
 * @Auther:刘兰斌
 * @Date: 2021/05/30/13:34
 * @Explain:

 *
 */
public class SortTest {
    public static void main(String[] args) {
        //集合元素规约reduce
        List<Integer> integers = Arrays.asList(24, 8, 35, 23, 11, 0, 6, 3);
        Integer res = integers.stream().reduce(0, (already, curr) ->  already + curr );
        //等价于
        Integer res2 = integers.stream().reduce(0, Integer::sum);
        System.out.println(res+" "+res2);
        List<String> strings = Arrays.asList("a", "sd", "b", "sb");
        String res3 = strings.stream().reduce("", (al, cur) -> al.concat(cur));
        System.out.println(res3);


        Employee e1 = new Employee(1,23,"F","Rick","Beethoven");
        Employee e2 = new Employee(2,13,"M","Rock","ven");
        Employee e3 = new Employee(3,73,"M","Re","oven");
        Employee e4 = new Employee(4,53,"F","james","Bee");
        Employee e5 = new Employee(5,63,"M","Raty","hove");
        Employee e6 = new Employee(6,33,"M","dtt","love");
        Employee e7 = new Employee(7,83,"F","yu","ko");
        Employee e8 = new Employee(8,103,"M","tu","so");
        Employee e9 = new Employee(9,113,"F","po","bye");
        Employee e10 = new Employee(10,123,"M","jo","all");
        List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
        Integer res5 = employees
                .parallelStream()//数据多时可以用并行流
                .map(s -> s.getAge())
                .reduce(0, Integer::sum);
        System.out.println(res5);
        //上面写法与下面等价
        Integer res6 = employees.parallelStream()
                .reduce(0, (subtotal, cur) -> subtotal + cur.getAge(), Integer::sum);
        System.out.println(res6);


    }
}

学习视频资源:https://www.bilibili.com/video/BV1sE411P7C1

你可能感兴趣的:(java,lambda,stream)