day22-JDK新特性

news2024/11/25 0:34:06

接口中的新特性

接口我们之前已经学过了,那么接口中内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法 (JDK 9)。

接口中可以有的内容

  • JDK1.7之前

    抽象方法

    常量

  • JDK1.8

    默认方法
    静态方法

  • JDK1.9

    私有方法

接口默认方法的定义和使用

默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。

默认方法定义格式

public default 返回值类型  方法的名称(参数列表){
    方法体
}

默认方法的好处

接口的默认方法,实现类可以不用重写,默认方法可以用于接口升级

/**
 * @Auther: yanqi
 * @Desc   实现类没有没重写默认方法呢?
 *              接口中的抽象方法是必须要重写(实现)
 *              接口中的默认方法,不用重写,也可以手动重写,你默认方法存在的意义?
 *
 *              如果今后项目代码已以经写好,后期可能要扩展,接口中加新的方法(功能),如果你加抽象方法(功能)
 *              所有的实现类有影响,所以针对以上后期可能要扩展功能的话,代码的维护性比较差,出现了默认方法
 */
  • 定义接口
    public interface LiveAble {
        //接口的默认方法
        public default void fly(){ 
            System.out.println("天上飞"); 
        } 
    }
    
  • 定义实现类
    public class Animal implements LiveAble {    
        // default 可以选择是否重写,也可以根据实际需求进行重写
        /*
        	@Override
       		public void fly() {
            	System.out.println("自由自在的飞");   
            }
        */
    }
    
  • 定义测试类
    public class InterfaceDemo {
        public static void main(String[] args) {       
            // 创建子类对象 
            Animal a = new Animal();
            // 调用默认方法
            a.fly();
        }
    }
    

接口静态方法的定义和使用

静态方法:使用 static 修饰,供接口直接调用。

静态与.class文件相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用

静态方法定义格式

public static 返回值类型 方法名称(参数列表){
    方法体
}

静态方法使用

  • 定义接口
    public interface LiveAble {
        //静态方法
        public static void show2(){
            System.out.println("静态方法-show2");
        }
    }
    
  • 定义实现类
    public class Animal implements LiveAble {    
      // 无法重写静态方法
    }
    
  • 定义测试类
    public class InterfaceDemo {
        public static void main(String[] args) {
            //无法调用
            // LiveAble l = new LiveAbleImpl();
            // l.show2();
            
            //接口名.静态方法(参数列表)
           LiveAble.show2();
        } 
    }
    

接口私有方法的定义和使用

如果一个接口中有多个默认方法,并且方法中有重复的内容,那么可以抽取出来,封装到私有方法中,供默认方法 去调用。从设计的角度讲,私有的方法是对默认方法和静态方法的辅助。

私有方法分类

  • 普通私有方法

    只有默认方法可以调用。

  • 私有静态方法

    默认方法和静态方法可以调用。

代码演示

  • 私有方法
    • 定义接口

      public interface MyInterfacePrivateA {
      	//默认方法
          public default void methodDefault1() {
              System.out.println("默认方法1");
              methodCommon();
          }
      
          //默认方法
          public default void methodDefault2() {
              System.out.println("默认方法2");
              methodCommon();
          }
      
          //普通-私有方法
          private void methodCommon() {
              System.out.println("AAA");
              System.out.println("BBB");
              System.out.println("CCC");
          }
      
      }
      
  • 私有静态方法

    • 定义接口

      public interface MyInterfacePrivateB {
          //静态方法
          public static void methodStatic1() {
              System.out.println("静态方法1");
              methodStaticCommon();
          }
      
          //静态方法
          public static void methodStatic2() {
              System.out.println("静态方法2");
              methodStaticCommon();
          }
      
          //私有-静态方法
          private static void methodStaticCommon() {
              System.out.println("AAA");
              System.out.println("BBB");
              System.out.println("CCC");
          }
      }
      

    私有方法主要解决的问题是:

默认方法和static方法代码重复的问题,private方法可作为抽取共性

Lambda表达式

什么是Lambda

Lambda 表达式是 Java8 新增的重要特性,Lambda 使 Java 具有了类似函数式编程的风格,其实 Lambda 表达式也是一个 “语法糖”,其实质也是由编译器根据表达式推断最终生成原始语法的字节码方式。

image-20211118115518550

面象对象思想:

做一件事情,找一个能解决这个事情的对象,调用这个对象的方法,完成事情

函数式编程思想:

只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程

函数式思想

函数式思想则尽量忽略面向对象的复杂语法:“强调做什么,而不是以什么形式去做”

而我们要学习的Lambda表达式就是函数式思想的体现

函数式接口

函数式接口在java中指的是:有且仅有一个抽象方法的接口

当然接口中可以有其他的方法(默认方法,静态方法,私有方法)
函数式接口的使用: 一般用作方法的参数和返回值类型

体验Lambda

  • 案例需求

    启动一个线程,在控制台输出一句话:多线程程序启动了

  • 实现步骤

    - 定义一个类MyRunnable实现Runnable接口,重写run()方法
    - 创建MyRunnable类的对象
    - 创建Thread类的对象,把MyRunnable的对象作为构造参数传递
    - 启动线程
    
  • 代码实现

    • 定义线程类
      public class MyRunnable implements Runnable {
      
          @Override
          public void run() {
              System.out.println("多线程程序启动了");
          }
      }
      
    • new Thread 方式
      //方式一
      MyRunnable my = new MyRunnable();
      Thread t = new Thread(my);
      t.start();
      
    • 匿名内部类方式
      //方式二
      new Thread(new Runnable() {
          @Override
          public void run() {
              System.out.println("多线程程序启动了");
          }
      }).start();
      
    • Lambda实现
      //方式三
      new Thread( () -> {
          System.out.println("多线程程序启动了");
      } ).start();
      

Lambda标准格式

  • 格式

    (形式参数) -> { 代码块 }

  • 格式解析
    • 形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可

    • ->:由英文中画线和大于符号组成,固定写法。代表指向动作

    • 代码块:是我们具体要做的事情,也就是以前我们写的方法体内容

Lambda表达式练习

Lambda表达式使用前提

  • 有一个接口
  • 接口中有且仅有一个抽象方法
/**
 * @Auther: yanqi
 * @Desc: 函数式接口在java中指的是:有且仅有一个抽象方法的接口
 *        当然接口中可以有其他的方法(默认方法,静态方法,私有方法)
          **函数式接口的使用: 一般用作方法的参数和返回值类型**
 *
 *          @FunctionalInterface
 *          作用:可以检测接口是不是一个函数式接口
 *              是:编译成功
 *              否:编译失败(接口中没有抽象方法,抽象方法多于1个)
 */

@FunctionalInterface
public interface LambdaInter{

    //定义一个抽象方法
    public abstract void method();

    // public abstract  void method2();//编译不通过,只能有一个抽象方法

}

抽象方法是无参无返回值

  • 实现步骤
    • 定义一个接口(Eatable),里面定义一个抽象方法:void eat();

    • 定义一个测试类(EatableDemo),在测试类中提供两个方法

      • 一个方法是:useEatable(Eatable e)

      • 一个方法是主方法,在主方法中调用useEatable方法

  • 代码实现
    //接口
    public interface Eatable {
        //抽象方法无参无返回值
        void eat();
    }
    //实现类
    public class EatableImpl implements Eatable {
        @Override
        public void eat() {
            System.out.println("一天一苹果,医生远离我");
        }
    }
    
    /** 
     * 测试类
     * @Auther: yanqi
     * @Desc **函数式接口的使用: 一般用作方法的参数和返回值类型**
     */
    public class EatableDemo {
        public static void main(String[] args) {
            //方式一:匿名内部类
            useEatable(new Eatable() {
                @Override
                public void eat() {
                    System.out.println("方式一:匿名内部类");
                }
            });
    
            //方式二:Lambda表达式
            //()表示eat()方法的参数列表,{}内部表示方法体
            useEatable(()->{
                System.out.println("方式二:Lambda表达式");
            });
        }
    
        //定义一个方法,参数用我们定义的函数式接口
        private static void useEatable(Eatable e) {
            e.eat();
        }
    
    }
    
    

抽象方法是有参无返回值

  • 实现步骤
    • 定义一个接口(Flyable),里面定义一个抽象方法:void fly(String s);

    • 定义一个测试类(FlyableDemo),在测试类中提供两个方法

      • 一个方法是:useFlyable(Flyable f)

      • 一个方法是主方法,在主方法中调用useFlyable方法

  • 代码实现
    public interface Flyable {
        //抽象方法是有参无返回值
        void fly(String s);
    }
    
    public class FlyableDemo {
        public static void main(String[] args) {
       
            //方式一:匿名内部类
            useFlyable(new Flyable() {
                @Override
                public void fly(String s) {
                    System.out.println(s);
                    System.out.println("飞机自驾游");
                }
            });
            System.out.println("--------");
    
            //方式二:Lambda表达式
            //useFlyable((String s) -> {
            useFlyable((s) -> { //类型也可以省略,lambda表达式会自己行判断类型   
                System.out.println(s);
                System.out.println("飞机自驾游");
            });
    
        }
    
        private static void useFlyable(Flyable f) {
            f.fly("风和日丽,晴空万里");
        }
    }
    

抽象方法是有参有返回值

  • 操作步骤
    • 定义一个接口(Addable),里面定义一个抽象方法:int add(int x,int y);

    • 定义一个测试类(AddableDemo),在测试类中提供两个方法

      • 一个方法是:useAddable(Addable a)

      • 一个方法是主方法,在主方法中调用useAddable方法

  • 代码实现
    public interface Addable {
        // 抽象方法是有参有返回值
        int add(int x,int y);
    }
    
    public class AddableDemo {
        public static void main(String[] args) {
            //方式一:匿名内部类
            useAddable(new Addable() {
                @Override
                public int add(int x, int y) {
                    return x+y;
                }
            });
            
            //方式二:lambda
            useAddable((int x,int y) -> {
                return x + y;
            });
            //可以省略类型
            useAddable((x,y)->{
               return x+y;
            });
            //如果代码块的语句只有一条,可以省略大括号和分号,和return关键字,不建议
            useAddable((x,y)->
                 x+y
            );
    
        }
    
        private static void useAddable(Addable a) {
            int sum = a.add(10, 20);
            System.out.println(sum);
        }
    }
    

Lambda表达式的省略模式

省略规则

  • 参数类型可以省略。但是有多个参数的情况下,不能只省略一个
  • 如果参数有且仅有一个,那么小括号可以省略
  • 如果代码块的语句只有一条,可以省略大括号和分号,和return关键字

代码演示

public interface Addable {
    int add(int x, int y);
}

public interface Flyable {
    void fly(String s);
}

public class LambdaDemo {
    public static void main(String[] args) {
//        useAddable((int x,int y) -> {
//            return x + y;
//        });
        //参数的类型可以省略
        useAddable((x, y) -> {
            return x + y;
        });

//        useFlyable((String s) -> {
//            System.out.println(s);
//        });
        //如果参数有且仅有一个,那么小括号可以省略
//        useFlyable(s -> {
//            System.out.println(s);
//        });

        //如果代码块的语句只有一条,可以省略大括号和分号
        useFlyable(s -> System.out.println(s));

        //如果代码块的语句只有一条,可以省略大括号和分号,如果有return,return也要省略掉
        useAddable((x, y) -> x + y);
    }

    private static void useFlyable(Flyable f) {
        f.fly("风和日丽,晴空万里");
    }

    private static void useAddable(Addable a) {
        int sum = a.add(10, 20);
        System.out.println(sum);
    }
}

Lambda表达式的注意事项

  • 使用Lambda必须要有接口,并且要求接口中有且仅有一个抽象方法

  • 必须有上下文环境,才能推导出Lambda对应的接口

    • 根据局部变量的赋值得知Lambda对应的接口

      Runnable r = () -> System.out.println(“Lambda表达式”);

    • 根据调用方法的参数得知Lambda对应的接口

      new Thread(() -> System.out.println(“Lambda表达式”)).start();

lambda表达式主要用于替换以前广泛使用的内部匿名类,使代码更简洁

Stream流

它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。

Stream(流)是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。

体验Stream流

  • 案例需求

    按照下面的要求完成集合的创建和遍历

    • 创建一个集合,存储多个字符串元素
    • 把集合中所有以"张"开头的元素存储到一个新的集合
    • 把"张"开头的集合中的长度为3的元素存储到一个新的集合
    • 遍历上一步得到的集合
  • 原始方式示例代码

    public class StreamDemo {
        public static void main(String[] args) {
            //1、创建一个集合,存储多个字符串元素
            ArrayList<String> list = new ArrayList<>();
            list.add("林青霞");
            list.add("张曼玉");
            list.add("王祖贤");
            list.add("柳岩");
            list.add("张敏");
            list.add("张无忌");
    
            //2、把集合中所有以"张"开头的元素存储到一个新的集合
            ArrayList<String> zhangList = new ArrayList<>();
            for(String s : list) {
                if(s.startsWith("张")) {
                    zhangList.add(s);
                }
            }
            System.out.println(zhangList);//[张曼玉, 张无忌]
    
            //3、把"张"开头的集合中的长度为3的元素存储到一个新的集合
            ArrayList<String> threeList = new ArrayList<>();
            for(String s : zhangList) {
                if(s.length() == 3) {
                    threeList.add(s);
                }
            }
            System.out.println(threeList);//张曼玉 张无忌
    
            //4、遍历上一步得到的集合
            for(String s : threeList) {
                System.out.println(s);
            }
        }
    }
    
  • 使用Stream流示例代码
    public class StreamDemo {
        public static void main(String[] args) {
            //创建一个集合,存储多个字符串元素
            ArrayList<String> list = new ArrayList<String>();
    
            list.add("林青霞");
            list.add("张曼玉");
            list.add("王祖贤");
            list.add("柳岩");
            list.add("张敏");
            list.add("张无忌");
    
            //Stream流来改进  s表示的list集合的String类型
            list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
            
            System.out.println("========遍历集合========");
            list.forEach(System.out::println);
            
            System.out.println("========遍历数组========");
            //定义数组
             String[] s = {"hello","world","java","yiyan"};
            //数组需要先转成流,才能使用
            Arrays.stream(s).forEach(System.out::println);
        }
    }
    

Stream流的好处

  • 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印

  • Stream流把真正的函数式编程风格引入到Java中

Stream流的思想

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QT2L6TDj-1673935761393)(assets/image-20210512182253047.png)]

获取Stream流的三种方式

  • Collection体系集合

    使用默认方法stream()生成流, default Stream stream()

  • Map体系集合

    把Map转成Set集合,间接的生成流

  • 数组

    通过Stream接口的静态方法of(T… values)生成流

3.3.2 代码演示

public class StreamDemo {
    public static void main(String[] args) {
        //Collection体系的集合可以使用默认方法stream()生成流
        List<String> list = new ArrayList<String>();
        Stream<String> listStream = list.stream();

        Set<String> set = new HashSet<String>();
        Stream<String> setStream = set.stream();

        //Map体系的集合间接的生成流
        Map<String,Integer> map = new HashMap<String, Integer>();
        Stream<String> keyStream = map.keySet().stream();
        Stream<Integer> valueStream = map.values().stream();
        Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();

        //数组可以通过Stream接口的静态方法of(T... values)生成流
        String[] strArray = {"hello","world","java"};
        Arrays.stream(strArray).forEach(System.out::println);
        Stream<String> strArrayStream = Stream.of(strArray);
        Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
        Stream<Integer> intStream = Stream.of(10, 20, 30);
    }
}

Stream流中间操作方法

概念

中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作。

  • 一个中间操作链,对数据源的数据进行处理。
  • 多个中间操作可以连接起来形成一个流水线

3.4.2 常见方法

方法名说明
Stream filter(Predicate predicate)用于对流中的数据进行过滤
Stream limit(long maxSize)返回此流中的元素组成的流,截取前指定参数个数的数据
Stream skip(long n)跳过指定参数个数的数据,返回由该流的剩余元素组成的流
static Stream concat(Stream a, Stream b)合并a和b两个流为一个流
Stream distinct()返回由该流的不同元素(根据Object.equals(Object) )组成的流
Stream sorted()返回由此流的元素组成的流,根据自然顺序排序
Stream map(Function mapper)返回由给定函数应用于此流的元素的结果组成的流
IntStream mapToInt(ToIntFunction mapper)返回一个IntStream其中包含将给定函数应用于此流的元素的结果

filter方法

用于对流中的数据进行过滤

public class StreamDemo01 {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素
        ArrayList<String> list = new ArrayList<String>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
        list.add("张敏");
        list.add("张无忌");

        //需求1:把list集合中以张开头的元素在控制台输出
        list.stream().filter(s -> s.startsWith("张")).forEach(System.out::println);
        System.out.println("--------");

        //需求2:把list集合中长度为3的元素在控制台输出
        list.stream().filter(s -> s.length() == 3).forEach(System.out::println);
        System.out.println("--------");

        //需求3:把list集合中以张开头的,长度为3的元素在控制台输出
        list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
                      
        //简化for循环
        list.forEach(System.out::println);
    }
}

limit&skip

返回此流中的元素组成的流,截取前指定参数个数和跳过指定个数的数据

public class StreamDemo02 {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素
        ArrayList<String> list = new ArrayList<String>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
        list.add("张敏");
        list.add("张无忌");

        //需求1:取前3个数据在控制台输出
        list.stream().limit(3).forEach(System.out::println);
        System.out.println("--------");

        //需求2:跳过3个元素,把剩下的元素在控制台输出
        list.stream().skip(3).forEach(System.out::println);
        System.out.println("--------");

        //需求3:跳过2个元素,把剩下的元素中前2个在控制台输出
        list.stream().skip(2).limit(2).forEach(System.out::println);

    }
}

concat&distinct

concat:将两个流合并成为一个流

distinct:由该流的不同元素(根据Object.equals(Object) )组成的流

public class StreamDemo03 {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素
        ArrayList<String> list = new ArrayList<String>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
        list.add("张敏");
        list.add("张无忌");

        //需求1:取前4个数据组成一个流
        Stream<String> s1 = list.stream().limit(4);
        s1.forEach(System.out::println);

        //需求2:跳过2个数据组成一个流
        Stream<String> s2 = list.stream().skip(2);
        s2.forEach(System.out::println);

        //需求3:合并需求1和需求2得到的流,并把结果在控制台输出
	   //Stream.concat(s1,s2).forEach(System.out::println);

        //需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
        Stream.concat(s1,s2).distinct().forEach(System.out::println);
    }
}

sorted

由此流的元素组成的流,根据自然顺序排序

public class StreamDemo04 {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素
        ArrayList<String> list = new ArrayList<String>();

        list.add("linqingxia");
        list.add("zhangmanyu");
        list.add("wangzuxian");
        list.add("liuyan");
        list.add("zhangmin");
        list.add("zhangwuji");

        //需求1:按照字母顺序把数据在控制台输出
		list.stream().sorted().forEach(System.out::println);
    }
}

map&mapToInt

map() 返回由给定函数应用于此流的元素的结果组成的流(将流中的元素映射到另一个流中)

mapToInt 计算流中的数据并返回结果

public class StreamDemo05 {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素
        ArrayList<String> list = new ArrayList<String>();

        list.add("10");
        list.add("20");
        list.add("30");
        list.add("40");
        list.add("50");

        //需求:将集合中的字符串数据转换为整数之后在控制台输出
       list.stream().map(s -> Integer.parseInt(s)).forEach(System.out::println);
       list.stream().map(Integer::parseInt).forEach(System.out::println);

        //int sum() 返回此流中元素的总和
        int result = list.stream().mapToInt(Integer::parseInt).sum();
        System.out.println(result);
    }
}

Stream流终结操作方法

概念

终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作。
一个终止操作,执行中间操作链,并产生结果。
这是Stream操作中的最后一步,终止操作,终止操作会从流的流水线生成结果
例如:List、Integer,甚至是 void 。

相关方法

方法名说明
void forEach(Consumer action)对此流的每个元素执行操作
long count()返回此流中的元素数

代码演示

public class StreamDemo {
    public static void main(String[] args) {
        //创建一个集合,存储多个字符串元素
        ArrayList<String> list = new ArrayList<String>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
        list.add("张敏");
        list.add("张无忌");

        //需求1:把集合中的元素在控制台输出,直接输出结果就不能返回stream对象了
//        list.stream().forEach(System.out::println);

        //需求2:统计集合中有几个以张开头的元素,并把统计结果在控制台输出
        long count = list.stream().filter(s -> s.startsWith("张")).count();
        System.out.println(count);
    }
}

Stream流综合练习

案例需求

现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作

  • 男演员只要名字为3个字的前三人

  • 女演员只要姓林的,并且不要第一个

  • 把过滤后的男演员姓名和女演员姓名合并到一起

  • 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据

演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法

Actor类

public class Actor {
    private String name;

    public Actor(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Actor{" +
                "name='" + name + '\'' +
                '}';
    }
}

案例代码

public class StreamTest {
    public static void main(String[] args) {
        //创建集合
        ArrayList<String> manList = new ArrayList<String>();
        manList.add("周润发");
        manList.add("成龙");
        manList.add("刘德华");
        manList.add("吴京");
        manList.add("周星驰");
        manList.add("李连杰");


        ArrayList<String> womanList = new ArrayList<String>();
        womanList.add("林心如");
        womanList.add("张曼玉");
        womanList.add("林青霞");
        womanList.add("柳岩");
        womanList.add("林志玲");
        womanList.add("王祖贤");

        //男演员只要名字为3个字的前三人
        Stream<String> manStream = manList.stream().filter(s -> s.length() == 3).limit(3);

        //女演员只要姓林的,并且不要第一个
        Stream<String> womanStream = womanList.stream().filter(s -> s.startsWith("林")).skip(1);

        //把过滤后的男演员姓名和女演员姓名合并到一起
        Stream<String> stream = Stream.concat(manStream, womanStream);

        //使用map映射到一个新的对象中
        stream.map(s -> new Actor(s)).forEach(System.out::println);
        stream.map(Actor :: new).forEach(System.out::println);
        stream.map(Actor :: new).forEach(a -> System.out.println(a.getName()));

		//
        Stream.concat(manList.stream().filter(s -> s.length() == 3).limit(3),
                womanList.stream().filter(s -> s.startsWith("林")).skip(1)).map(Actor::new).
                forEach(p -> System.out.println(p.getName()));
    }
}

Stream流的收集操作

概念

对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中。

常用方法

方法名说明
R collect(Collector collector)把结果收集到集合中
  • 工具类Collectors提供了具体的收集方式
方法名说明
public static Collectors toList()把元素收集到List集合中
public static Collectors toSet()把元素收集到Set集合中
public static Collectors toMap(Function keyMapper,Function valueMapper)把元素收集到Map集合中

代码演示

public class CollectDemo {
    public static void main(String[] args) {
        //创建List集合对象
        List<String> list = new ArrayList<String>();
        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");

        /*
        //需求1:得到名字为3个字的流
        Stream<String> listStream = list.stream().filter(s -> s.length() == 3);

        //需求2:把使用Stream流操作完毕的数据收集到List集合中并遍历
        List<String> names = listStream.collect(Collectors.toList());
	    names.stream().forEach(System.out::println);
        */

        //创建Set集合对象
        Set<Integer> set = new HashSet<Integer>();
        set.add(10);
        set.add(20);
        set.add(30);
        set.add(33);
        set.add(35);

        /*
        //需求3:得到年龄大于25的流
        Stream<Integer> setStream = set.stream().filter(age -> age > 25);

        //需求4:把使用Stream流操作完毕的数据收集到Set集合中并遍历
        Set<Integer> ages = setStream.collect(Collectors.toSet());
        ages.stream().forEach(System.out::println);
        */
        //定义一个字符串数组,每一个字符串数据由姓名数据和年龄数据组合而成
        String[] strArray = {"林青霞,30", "张曼玉,35", "王祖贤,33", "柳岩,25"};

        //需求5:得到字符串中年龄数据大于28的流
        Stream<String> arrayStream = Stream.of(strArray).filter(s -> Integer.parseInt(s.split(",")[1]) > 28);

        //需求6:把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名作键,年龄作值
        //toMap(林青霞,30)
        Map<String, Integer> map = arrayStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1])));

        Set<String> keySet = map.keySet();
        for (String key : keySet) {
            Integer value = map.get(key);
            System.out.println(key + "," + value);
        } 
       //要把map间接转成collection体系下的集合,可以使用stream流
        map.keySet().stream().forEach(System.out::println);
        map.values().stream().forEach(System.out::println);
        System.out.println("-----------------");
        map.keySet().stream().forEach(s -> System.out.println(s+":"+map.get(s )));
    }
}

流操作完毕的数据收集到Set集合中并遍历
Set ages = setStream.collect(Collectors.toSet());
ages.stream().forEach(System.out::println);
*/
//定义一个字符串数组,每一个字符串数据由姓名数据和年龄数据组合而成
String[] strArray = {“林青霞,30”, “张曼玉,35”, “王祖贤,33”, “柳岩,25”};

    //需求5:得到字符串中年龄数据大于28的流
    Stream<String> arrayStream = Stream.of(strArray).filter(s -> Integer.parseInt(s.split(",")[1]) > 28);

    //需求6:把使用Stream流操作完毕的数据收集到Map集合中并遍历,字符串中的姓名作键,年龄作值
    //toMap(林青霞,30)
    Map<String, Integer> map = arrayStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1])));

    Set<String> keySet = map.keySet();
    for (String key : keySet) {
        Integer value = map.get(key);
        System.out.println(key + "," + value);
    } 
   //要把map间接转成collection体系下的集合,可以使用stream流
    map.keySet().stream().forEach(System.out::println);
    map.values().stream().forEach(System.out::println);
    System.out.println("-----------------");
    map.keySet().stream().forEach(s -> System.out.println(s+":"+map.get(s )));
}

}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/168269.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用Navicat导入和导出sql语句

创建mysql数据库 创建数据库之前&#xff0c;肯定要先连接上数据库&#xff0c;如果不知道怎么使用navicat连接mysql数据库&#xff0c;可以参考之前的文章哦 https://blog.csdn.net/weixin_43860634/article/details/128716733 接下来进入正题 1、首先要双击test &#xff0…

命令注入与dvwa中的Command Injection

一、什么是命令注入&#xff1f;即 Command Injection&#xff0c;是指通过提交恶意构造的参数破坏命令语句结构&#xff0c;从而达到执行恶意命令的目的。此攻击与代码注入不同&#xff0c;因为代码注入允许攻击者添加自己的代码&#xff0c;然后由应用程序执行。 在命令注入中…

用队列实现栈

题目&#xff1a;225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09;准备工作这题明确说明了需要用队列来实现栈&#xff0c;介于C语言没有队列的库&#xff0c;所以在此之前我们需要用调用之前学的队列&#xff0c;详见队列typedef int QDataType;typedef struct Queu…

Ubuntu上安装 Hadoop 3详细过程(验证+填坑总结)

Ubuntu上安装 Hadoop 3 前提条件&#xff1a; Python 推荐3.8JDK 推荐1.8 解压安装 sudo tar -zxvf hadoop-3.3.0.tar.gz -C /usr/local cd /usr/local sudo mv hadoop-3.3.0 hadoop sudo chown -R hadoop ./hadoop 配置环境变量 vim ~/.bashrc # hadoop export H…

云原生安全系列 5:ETCD 安全加固

引言 etcd是一个强一致性的分布式键值存储&#xff0c;它提供了一种可靠的方式来存储需要被分布式系统或机器集群访问的数据。通过 raft 算法它能在网络分区期间优雅地处理领导者的选举&#xff0c;并能容忍机器故障&#xff0c;甚至在领导者节点上。除此之外&#xff0c; etc…

存储过程的基础知识

本文来简单说下存储过程的基础知识 文章目录概述什么是存储过程存储过程的优缺点概述 mysql官网提供的储存过程&#xff1a;https://www.mysqlzh.com/doc/225/499.html 什么是存储过程 简单的说&#xff0c;存储过程是一条或者多条SQL语句的集合&#xff0c;可视为批文件&…

Windows下更改yarn的安装位置,减小C盘占用

Windows下更改yarn的安装位置&#xff0c;减小C盘占用 绷不住了&#xff0c;yarn的C盘占用太高了&#xff0c;我这C盘感觉以后会受不了&#xff0c;太大了~~&#xff08;捂脸~~ nnd&#xff0c;撸他&#xff0c;更改yarn的位置开始&#xff01; 先看看yarn目前的位置 检查当前…

「自控原理」2.4 信号流图与梅逊公式、闭环传递函数

本节引入了信号流图以及梅逊增益公式&#xff0c;可以据此快速对系统进行化简 本节引入了闭环传递函数的概念&#xff0c;并介绍了常用的闭环传递函数 文章目录信号流图的基本概念信号流图与方框图的关系从结构图绘制信号流图从信号流图绘制结构图梅逊(Mason)增益公式Mason公式…

Workfine5.0扩展功能——如何识别身份证信息?

哈喽&#xff0c;我是办公助手小W&#xff0c;又到了跟大家分享办公小技巧的时候啦&#xff01; 最近Workfine5.0最新版本上线后&#xff0c;大家最感兴趣的就是它的扩展功能了&#xff0c;今天要跟大家分享的就是如何实现身份证信息的提取。 首先咱们先要知道如何下载安装扩…

(第五章)OpenGL超级宝典学习:缓冲

缓冲 前言 本篇在讲什么 关于OpenGL数据缓冲的相关内容 本篇适合什么 适合初学OpenGL的小白 想了解OpenGL缓冲对象的同学 本篇需要什么 对C语法有简单认知 对OpenGL有简单认知 最好是有OpenGL超级宝典蓝宝书 依赖Visual Studio编辑器 本篇的特色 具有全流程的图文…

使用OpenCV透视变换技术实现坐标变换实践

1. 概述 1.1. 需求 在局部空间&#xff08;无GPS定位&#xff09;视频监控过程中&#xff0c;把视频识别到物体位置&#xff0c;投射到空间平面坐标系中&#xff0c;获取物体在局部空间的平面坐标。 1.2. 解决方案 使用图像透视变换技术。 1.3. 透视变换概念 透视变换是指…

链路追踪组件Skywalking使用

前言Skywalking是一个国产开源框架&#xff0c;2015年由吴晟开源 &#xff0c; 2017年加入Apache孵化器&#xff0c;其用于追踪多微服务模块调用之间日志的追踪&#xff0c;协助程序员进行排除问题Skywalking架构Skywalking架构图大概如下SkyWalking OAP&#xff1a; SkyWalkin…

如何格式化U盘?以及优盘格式化的恢复方法

我们经常使用U盘来进行存储和传输数据&#xff0c;使用时间久了&#xff0c;可能需要我们进行优盘格式化。需要注意&#xff01;优盘格式化之前&#xff0c;记得对里面的数据进行备份&#xff0c;防止数据清空造成不必要的损失。 如何进行U盘格式化&#xff1f;格式化优盘后&a…

“深度学习”学习日记。误差反向传播法--加法层、乘法层、激活函数层的实现

2023.1.16 1、加法层、乘法层&#xff1a; 前两篇文章都在讲述理论&#xff0c;今天实现代码操作&#xff1a;关于加法节点&#xff0c;乘法节点的内容在这篇文章。 https://blog.csdn.net/m0_72675651/article/details/128695488 在以后的学习中&#xff0c;将把构建神经网…

AHOcoder声码器

AHOcoder声码器 目前最常见的声码器有WORLD&#xff0c;STRAIGHT&#xff0c;&#xff27;riffin_Lim等&#xff0c;AHocoder算是少见的&#xff0c;但也可以学习一下。 代码下载网址&#xff1a;AHOcoder 简介 AHOcoder 语音声码器由 Daniel Erro 在巴斯克大学的 AHOLAB 信…

若依配置教程(一)运行若依系统

一、下载源代码 若依的源代码是开源的&#xff0c;所以我们在若依的官方网站即可进行下载&#xff0c;若依的官网是&#xff1a;http://doc.ruoyi.vip/ruoyi-vue/&#xff0c;进入官网后&#xff0c;会显示代码下载的地址&#xff1a;https://gitee.com/y_project/RuoYi-Vue&a…

【进阶】Bean作用域和生命周期

努力经营当下&#xff0c;直至未来明朗&#xff01; 文章目录一、通过⼀个案例来看 Bean 作⽤域的问题1. 被修改的Bean案例2. 原因分析二、作用域Scope定义1. Bean的六种作用域&#xff08;重点&#xff09;1&#xff09;singleton2&#xff09;prototype3&#xff09;request4…

JVM——类加载与字节码技术(2)

三、编译期处理 所谓的 语法糖 &#xff0c;其实就是指 java 编译器把* .java 源码编译为* .class 字节码的过程中&#xff0c;自动生成和转换的一些代码&#xff0c;主要是为了减轻程序员的负担&#xff0c;算是 java 编译器给我们的一个额外福利 【注意】以下代码的分析&am…

Python爬虫之基于 selenium 实现文献信息获取

目录初识 selenium网页分析代码实现踩过的坑最近有小伙伴后台跟我说&#xff0c;临近毕业&#xff0c;写毕业论文需要上知网查找大量的文献&#xff0c;但是一篇一篇看文献信息以及文献摘要又有点麻烦&#xff0c;能不能让我写一个爬虫去批量获取文献相关信息 我一听好家伙&am…

【算法】二叉树遍历

目录1.概述2.代码实现2.1.二叉树定义2.2.前序遍历2.3.中序遍历2.4.后序遍历2.5.层序遍历3.应用本文参考&#xff1a; LABULADONG 的算法网站 1.概述 &#xff08;1&#xff09;所谓遍历 (Traversal) 是指沿着某条搜索路线&#xff0c;依次对树中每个结点均做一次且仅做一次访问…