stream流小结(一) 2021-09-27

一.Stream流的总结
Stream流的思想:
    获取方法 -->  中间方法 --> 终结方法

获取方法:
    创建一条流水线,并把数据放到流水线上准备进行操作

中间方法:
    流水线上的操作
    一次操作完毕之后,还可以进行其他操作

终结方法:
    一个Stream流只能有一个终结方法
    是流水线上的最后一个操作

二.Stream流的获取方法
1.单列集合
    可以使用Collection接口中的默认方法stream()生成流
    default Stream<E> stream
    代码示例:
 

private static void method1() {
        ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        // Stream<String> stream = list.stream();
        // stream.forEach(s-> System.out.println(s));
        list.stream().forEach(s-> System.out.println(s));
    }

2.双列集合
     间接 的生成流
    可以先通过keySet或者entrySet获取一个Set集合,再获取Stream流
    集合对象.keySet().stream();
     集合对象.entrySet().stream();
     代码示例:

private static void method2() {
        HashMap<String, Integer> stringIntegerHashMap = new HashMap<>();
        stringIntegerHashMap.put("zhangsan", 23);
        stringIntegerHashMap.put("lisi", 24);
        stringIntegerHashMap.put("wangwu", 25);
        stringIntegerHashMap.put("zhaoliu", 26);
        stringIntegerHashMap.put("qianqi", 27);
        // 双列集合不能直接获取Stream流
        // keySet 先获取到所有的键,再把这个Set集合中所有的键放到Stream流中
        stringIntegerHashMap.keySet().stream().forEach(s -> System.out.println(s));
        // entrySet
        // 先获取到所有的键值对对象,再把这个Set集合中所有的键值对对象放到Stream流中
        stringIntegerHashMap.entrySet().stream().forEach(s -> System.out.println(s));
    }

3.数组
    Arrays中的静态方法Stream生成流
    代码示例:
    private static void method3() {
        int[] arr = {1, 2, 3, 4, 5};
        Arrays.stream(arr).forEach(s -> System.out.println(s));
    }

4.同种数据类型的多个数据
    1,2,3,4,5....
    "aaa","bbb","ccc"...
    使用Stream.of(T...value)            T...value,这个形参是一个可变参数
    代码示例:
    private static void method4() {
        Stream.of(1, 2, 3, 4, 5, 6).forEach(s -> System.out.println(s));
    }

三.中间方法
1.filter()
    Stream<T> filter(Predicate predicate):过滤    
    Predicate接口:    Predicate接口是个断言式接口.,其参数是<T,boolean>,也就是给一个参数T,返回boolean类型的结果.

Predicate接口中的方法:    boolean rest(T t):对给定的参数进行判断,返回一个boolean值
    filter方法获取流中的每一个数据,而test方法中对s进行判断就可以了.如果判断结果为true,则当前数据留下,如果判断结果为false,则当前数据就不要了.

代码示例:

ArrayList<String> list = new ArrayList<>();
        list.add("张三丰");
        list.add("张无忌");
        list.add("张翠山");
        list.add("王二麻子");
        list.add("张良");
        list.add("谢广坤");
        /*list.stream().filter(
                new Predicate<String>() {
                    @Override
                    public boolean test(String s) {
                        boolean result = s.startsWith("张");
                        return result;
                    }
                }
            ).forEach(s -> System.out.println(s));*/
        /*list.stream().filter((String s)->{
            boolean result = s.startsWith("张");
            return result;
        }).forEach(s-> System.out.println(s));*/
        
        list.stream().filter(s->s.startsWith("张")).forEach(s-> System.out.println(s));

2.其他方法
(1)Stream<T> limit(long maxSize):截取指定参数个数的数据    这个方法保留的是前面的数据
(2)Stream<T> skip(long n):跳过指定参数个数的数据    去除前面的数据,保留后面的数据
(3)static <T> Stream<T> concat​(Stream a, Stream b):合并a和b两个流为一个流
(4)Stream<T> distinct():去除流中重复的元素.依赖(hashCode和equals方法)

四.终结方法
1.foreach()
2.count()

五.Stream流的收集方法
使用Stream流的方式操作完毕之后,我想把流中的数据收集起来,该怎么办

Stream流的手机方法
R collect(Collector collector)

工具类Collectors提供了具体的手机方法
public static <T> Collector toList():把元素收集到List集合中
public static <T> Collector toSet():把元素收集到Set集合中
public static Collector toMap(Function keyMapper,Function valueMapper):把元素收集到Map集合中

六.Java中的::是什么意思?
.forEach(element -> {System.out.println(element)})
但是System.out.println的参数和传递的参数element 的类型完全匹配,所以这样的时候就可以简化为:
.forEach(System.out::println)

forEach方法的源码:

default void foreach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
         action.accept(t);
    }
}

其实它本质上是调用了for循环,它的参数的是一个Consumer对象,在for循环中调用了对象的accept方法。
注意该方法是接口的default方法,是JDK8新增的语法。至于为什么可以写成System.out::println,这种语法叫做方法引用。
该功能特性也是JDK8以后引入的,你可以把它看做拉姆达表达式的语法糖。
如果我们不这样写的话,我们可以用拉姆达表达式改写成以下代码:

list.forEach((t) -> System.out.println(t));
如果还不明白的话,也可以这样:
list.forEach((String t) -> System.out.println(t));
这样的效果跟System.out::println是一样的。

Lambda表达式允许4中方式的双冒号:

种类    使用方法对应的lambda表达式
(1)引用特定对象的实例方法Object::instanceMethod(a,b,...) -> 特定对象,实例方法(a,b,...)
(2)引用类方法Class::staticMethod(a,b,...) -> 类名.类方法(a,b,...)
(3)引用某类对象的实例方法Class::instanceMethod(a,b,...) -> a.实例方法(b,...)
(4)引用构造器Class::new(a,b,...) -> new 类名(a,b,...)

其中的Class指的是类名,产生于class Class{}
object是实例对象,产生于Class object = new Class;

object::instanceMethod  的一个典型用法就是 System.out::println out继承于FilterOutputStream,可以看成System的一个成员对象,通过它可以调用printstream中的输出方法。

System.out是printStream的实例: 因为System类当中的out 数据成员是由printStream流创建出来的对象,在system类中为public static final printStream out  而且out又是static的,所以只能够通过system来调用,即为System.out了。

System.out说是printStream的实例化对象,意思就是说System类当中的out数据成员即为printStream 类的对象了。System.out 整个就表示屏幕输出了,这时候还只是字节流而已,当调用pringStream的方法println()是就表示用什么用的方式打印输出的关系了。

在此请回看 Consumer 类的代码,就明白了为什么 ```Consumer one = System.out::println``` 是 ```Consumer one = t -> System.out.println(t)``` 的简写,
在这里插一个多线程的lambda表达式使用技巧:

public class SynchronizedTest {
    public synchronized void method1() {
        System.out.println("Method 1 start");
        try {
            System.out.println("Method 1 execute");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Method 1 end");
    }

    public synchronized void method2() {
        System.out.println("Method 2 start");
        try {
            System.out.println("Method 2 execute");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Method 2 end");
    }

     public static void main(String[] args) {
        // 一种最简洁的启动方法
//        new Thread( ()-> new SynchronizedTest().method1() ).start();
        //新建实例对象的启动方法
        final SynchronizedTest test = new SynchronizedTest();
        new Thread(test::method1).start();
        new Thread( ()-> test.method1() ).start();
        //显式的赋值Runnable后再启动
        Runnable tt = test::method1;
        new Thread(tt).start();
        //
        new Thread(test::method2).start();

        //运行完后对结果有没有疑问? 为什么2后面还有1?
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值