快速了解Stream流

快速了解Stream流

      • 一.函数式接口
        • 1.函数型接口Function
        • 2.断定性接口Predicate
        • 3.消费型接口Consumer
        • 4.供给型接口Supplier
      • 二.Stream流式计算
        • 1.生成串行流
        • 2.stream流的注意事项
        • 3.foreach
        • 4.filter
        • 5.limit
        • 6.skip
        • 7.map
        • 8.sorted
        • 9.distinct
        • 10.match
        • 11.min max
        • 12.map reduce
        • 13.mapTo
        • 14.collect
        • 15.关于并行流
        • 16.ForkJoin

一.函数式接口

函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口

interface MathOperation {  // 函数式接口
   int operation(int a, int b);
}

函数式接口可以被隐式转换为 lambda 表达式

(parameters) -> expression
或
(parameters) ->{ statements; }

Lambda表达式(也可称为闭包)就是一个匿名函数(匿名方法)

1.函数型接口Function

特点:有传入参数,有返回值
快速了解Stream流_第1张图片

public class FunctionInter {
    public static void main(String[] args) {
       Function function = (age)->{return "我今年"+age+"岁";};
        System.out.println(function.apply(10));
    }
}

快速了解Stream流_第2张图片

2.断定性接口Predicate

特点:有传入参数,进行判断,返回一个布尔值
快速了解Stream流_第3张图片

public class FunctionInter {
    public static void main(String[] args) {
        Predicate<Integer> predicate = (num)->{return num == 0;};

        System.out.println(predicate.test(1));
    }
}

快速了解Stream流_第4张图片

3.消费型接口Consumer

特点:只有输入,没有返回值
快速了解Stream流_第5张图片

public class FunctionInter {
    public static void main(String[] args) {
        Consumer consumer = (str)->{
            System.out.println(str);
        };

        consumer.accept("zhang");
    }
}

快速了解Stream流_第6张图片

4.供给型接口Supplier

特点:没有参数,只有返回值
快速了解Stream流_第7张图片

public class FunctionInter {
    public static void main(String[] args) {
        Supplier supplier = ()->{return 1024;};
        System.out.println(supplier.get());
    }
}

快速了解Stream流_第8张图片

二.Stream流式计算

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果

Stream流不保存数据,只是对数据加工处理

±-------------------+ ±-----+ ±-----+ ±–+ ±------+
| stream of elements ±----> |filter±> |sorted±> |map±> |collect|
±-------------------+ ±-----+ ±-----+ ±–+ ±------+

1.生成串行流

  • stream() − 为集合创建串行流
  • Stream.of(T1,T2,T3…) of方法创建一个流,可以是各种类型
public class Demo1 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        Stream<String> stream = list.stream();

        Set<String> set = new HashSet<>();
        Stream<String> stream1 = set.stream();
        
        HashMap<Integer, String> map = new HashMap<>();

        Stream<Integer> stream2 = map.keySet().stream();
        Stream<String> stream3 = map.values().stream();

        Stream<Map.Entry<Integer, String>> stream4 = map.entrySet().stream();
    }
}

2.stream流的注意事项

  • 一个Stream流只能操作一次
  • Stream流操作后返回的是新的流
  • Stream流必须调用终结方法,比如foreach、count,或者进行数据收集collect,否则中间的不会执行

3.foreach

foreach是一个消费型接口,主要用来遍历集合
在这里插入图片描述

public class ForEach {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("zhang");
        list.add("liu");
        list.add("wang");

        list.stream().forEach((str)->{
            System.out.println(str);
        });

        list.stream().forEach(  // :: 这个符号代表方法调用
            System.out::println
        );
    }
}

快速了解Stream流_第9张图片

4.filter

flter是一个断定型接口,主要用来选择符合条件的集合数据
在这里插入图片描述

public class Filter {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("zhang");
        list.add("liu");
        list.add("wang");

        list.stream().filter((str)->{
            return str.length()>3;
        }).forEach(s -> {
            System.out.println("长度大于3的姓氏"+s);
        });
    }
}

5.limit

主要用来选择前几个集合数据
在这里插入图片描述

public class Limit {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("zhang");
        list.add("liu");
        list.add("wang");

        list.stream().limit(2).forEach(System.out::println); // 获取前两个数组
    }
}

快速了解Stream流_第10张图片

6.skip

主要用来选择后面几个数据
快速了解Stream流_第11张图片

public class Skip {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("zhang");
        list.add("liu");
        list.add("wang");

        list.stream().skip(2).forEach(System.out::println); // 跳过前两个数据
    }
}

快速了解Stream流_第12张图片

7.map

函数型接口,map可以将流的类型变成另外一种类型,返回的依旧是Stream流

在这里插入图片描述

调用map方法,将每一个字符串类型变成字符数组类型!调用foreach循环遍历每一个数组arr,对arr遍历输出每一个字符

public class MapTest {
public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("zhang");
    list.add("liu");
    list.add("wang");

    list.stream().map((s) -> s.toCharArray()).forEach((arr) -> {
        for (char c : arr) {
            System.out.println(c);
        }
    });     
}

快速了解Stream流_第13张图片

8.sorted

主要用来对集合数据排序,分为无参数和有参数(下图)两种

在这里插入图片描述

public class Sort {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(4);
        list.add(64);
        list.add(1024);
        list.add(2048);
        list.add(64);


        list.stream().sorted().forEach(System.out::println);  // 无参数排序,自然排序

        System.out.println("===========");

        list.stream().sorted((Integer o1,Integer o2) -> {  // 自定义降序排序
            return o2 - o1;
        }).forEach(System.out::println);
    }
}

快速了解Stream流_第14张图片

9.distinct

主要用来去重集合数据

public class Distinct {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(4);
        list.add(64);
        list.add(1024);
        list.add(2048);
        list.add(64);

        list.stream().distinct().forEach(System.out::println);
    }
}

快速了解Stream流_第15张图片

注意,如果是自定义的对象,去重会失败,我们必须重写类的eaquls更改判断条件才可以实现去重

10.match

判断集合的元素是否满足某个条件,是断定型接口

在这里插入图片描述

public class Match {
    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
        Stream<Integer> stream1 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
        Stream<Integer> stream2 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流

        boolean res = stream.allMatch((num) -> {  // 是否都大于40?
            return num > 40;
        });

        System.out.println(res);

        boolean res2 = stream1.anyMatch((num) -> {
            return num > 99;   // 是否有大于99的数据?
        });
        System.out.println(res2);

        boolean res3 = stream2.noneMatch((num) ->{  // 是否没有小于0的元素?
            return num < 0;
        });
        System.out.println(res3);
    }
}

快速了解Stream流_第16张图片

11.min max

主要用来获取集合中的最大值和最小值,注意,必须要指定一个比较器

快速了解Stream流_第17张图片

public class Max_Min {
    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
        Stream<Integer> stream1 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流

        // 升序,max取最后一个数据
        Optional<Integer> max = stream.max(((o1, o2) -> o1 - o2));
        System.out.println(max.get());

        Optional<Integer> min = stream1.min(((o1, o2) -> o1 - o2));
        System.out.println(min.get());

    }
}

12.map reduce

主要用来选取一些数据进行处理

map是一个Function接口
在这里插入图片描述

public class MapReduce {
    //
    public static void main(String[] args) {
        Stream<Person> stream = Stream.of(
                new Person("jack",18),
                new Person("rose",26),
                new Person("ac",23)
        ); // of一个流

        stream.map((person) ->{
            return person.getAge(); // 获取年龄
        }).reduce(0,Math::max);  // 0代表默认值,比如第一次0和18会比较,18大,18在和26比.....
    }
}

快速了解Stream流_第18张图片

13.mapTo

快速了解Stream流_第19张图片
主要应用:将Integer集合转换成int数组

    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(10, 50, 24, 6, 8, 100); // of一个流

        int[] ints = stream.mapToInt((num) -> num.intValue()).toArray();
        for (int i : ints) {
            System.out.println(i);
        }
    }
}

快速了解Stream流_第20张图片

14.collect

进行数据收集,将数据收集到一个新的集合

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("zhang");
    list.add("liu");
    list.add("wang");

    ArrayList<String> collect = list.stream().filter((str) -> {
        return str.length() > 3;
    }).collect(Collectors.toCollection(ArrayList::new));
      
   List<Integer> integerList = stream6.collect(Collectors.toList());
}
public class Collect {
    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
        Stream<Integer> stream1 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
        Stream<Integer> stream2 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
        Stream<Integer> stream3 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
        Stream<Integer> stream4 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
        Stream<Integer> stream5 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
        Stream<Integer> stream6 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流


        Optional<Integer> max = stream.collect(Collectors.maxBy((o1, o2) -> o1 - o2));  // 获取最大值
        System.out.println("最大值"+max.get());

        Optional<Integer> min = stream1.collect(Collectors.minBy((o1, o2) -> o1 - o2)); // 最小值
        System.out.println("最小值"+min.get());

        IntSummaryStatistics sum = stream2.collect(Collectors.summarizingInt((num) -> num));// 总和,ToIntFunction接口
        System.out.println("总和"+sum.toString());

        Double avg = stream3.collect(Collectors.averagingInt((num) -> num));// 平均值,ToIntFunction接口
        System.out.println("平均值"+avg);

        Map<String, List<Integer>> map = stream4.collect(Collectors.groupingBy((num) -> {
            if (num > 60) return "大于60的一组";
            else return "小于60的组";
        }));
        map.forEach((K,V) ->{
            System.out.println(K +":"+V);
        });


        Map<Boolean, List<Integer>> booleanListMap = stream5.collect(Collectors.partitioningBy((num) -> {  // 根据条件的布尔值进行分区
            return num > 60;
        }));
        booleanListMap.forEach((K,V) ->{
            System.out.println(K +":"+V);
        });

    }
}

快速了解Stream流_第21张图片

15.关于并行流

  • 对流调用一下parallel()就可以获取到一个并行流
  • 使用Collection接口提供给我们parallelStream()也可以获取到一个并行流

示例

public class Parallel {
    public static void main(String[] args) {
        Stream<Integer> stream2 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流

        Stream<Integer> parallel = stream2.parallel();

        parallel.filter((num) -> {
            System.out.println(Thread.currentThread().getName()+"处理了数字"+num);
            return num > 20;
        }).forEach((num) ->{
            System.out.println(num+"大于20");
        });
    }
}

快速了解Stream流_第22张图片

可以看到多个线程处理了这个流,因此效率比较高,当然因为是多线程,处理不当会引起问题

解决线程不安全的方法

  • 用同步代码块
  • 使用collec、toArray
  • 使用线程安全的集合类

16.ForkJoin

我们注意到,上面有的线程出现了ForkJoinPool,那ForkJoin是什么?

Fork/Join模块

  • 线程池 ForkJoin
  • 任务对象 ForkJoinTask
  • 执行任务得线程 ForkJoinWorkerThread

原理

分治法

if(任务很小){
    直接计算得到结果
}else{
    分拆成N个子任务
    调用子任务的fork()进行计算
    调用子任务的join()合并计算结果
}

快速了解Stream流_第23张图片

工作窃取

第二个队列工作完成,会把其他队列的任务拿过来执行
快速了解Stream流_第24张图片

案例

计算1-1000000的和

思路:我们将任务拆分,小于2000的直接计算,否则进行拆分

实现:继承RecursiveTask,重写compute方法

public class ForkJoinTest {
    public static void main(String[] args) {
        ForkJoinPool forkJoinPool = new ForkJoinPool();

        SumTask sumTask = new SumTask(1,10000000);
        long start = System.currentTimeMillis();
        Long res = forkJoinPool.invoke(sumTask);
        long end = System.currentTimeMillis();
        System.out.println(res);
        System.out.println(end - start);
    }
}

class SumTask extends RecursiveTask<Long>{
    private static final long THRESHOLD = 2000L;

    private final long start;
    private final long end;

    SumTask(long start, long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        long length = end - start; // 计算数的长度

        if(length <= THRESHOLD){  // 计算
            long count = 0;
            for (long i = start; i <= end; i++) {
                count += i;
            }
            return count;
        }else{  // 拆分
            long mid = (start+end) / 2;
            SumTask left = new SumTask(start,mid);
            left.fork();
            SumTask right = new SumTask(mid+1,end);
            right.fork();

            return left.join() + right.join();
        }
    }
}

快速了解Stream流_第25张图片

你可能感兴趣的:(Java,java,开发语言)