Java学习笔记day19-可变参数-Stream流

Day19

可变参数

可变参数:就是形参的个数是可以变化的

  • 格式:修饰符 返回值类型 方法名(数据类型… 变量名){}
  • 范例:public static int sum(int… a){}
  • 这里的变量其实是一个数组
  • 如果一个方法有多个参数,包含可变参数,可变参数要放在最后

示例:

public class ChangeableTest {
    public static void main(String[] args) {
        //调用方法传递数组中的值
        int sum = getSum(1,2,3,4,5);
        System.out.println("sum = "+sum); //sum = 15
    }
    //创建一个求和方法,以数组为可变参数
    public static int getSum(int... arr){
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum += arr[i];
        }
        return sum; 
    }
}
创建不可变的集合
方法名说明
static List of(E…elements)创建一个具有指定元素的List集合对象
static Set of(E…elements)创建一个具有指定元素的Set集合对象
static <K,V> Map<K,V> of(E…elements)创建一个具有指定元素的Map集合对象

示例:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class BubianTest {
    public static void main(String[] args) {
        //集合的批量添加
        //首先通过调用List.of方法来创建一个不可变的集合,of方法的形参就是一个可变参数
        //再创建一个ArrayList集合,并把这个不可变的集合中所有的数据,都添加到ArrayList中
        ArrayList<String> list = new ArrayList<>(List.of("a","b","c","d"));
        System.out.println(list);

        //set集合传递的参数不能重复
        Set<String> set = Set.of("a","b","c","d");
        System.out.println(set);

        Map<String, String> map = Map.of("三三", "陕西", "东东", "沈阳", "西西", "西安");
        System.out.println(map);

        Map<String,String> map1 = Map.ofEntries(Map.entry("三三","陕西"),
                Map.entry("东东","沈阳"),
                Map.entry("西西","西安"));
        System.out.println(map1);
    }
}

总结

  • 在List、Set、Map接口中,都存在of方法,创建一个不可变的集合;
  • 这个集合不能添加、不能删除、不能修改;
  • 但是可以结合集合的带参构造,实现集合的批量添加;
  • 在Map接口中,还有一个ofEntries方法可以提高代码的阅读性;
  • 首先会把键值对封装成一个Entry对象,再把这个Entry对象添加到集合中。
Stream流
Stream流的三类方法
  • 获取Stream流;创建一条流水线,并把数据放到流水线上准备进行操作。
  • 中间方法;流水线上的操作,一次操作完毕之后,还可以继续进行其他操作。
  • 终结方法;一个Stream流只能有一个终结方法,是流水线上的最后一个操作。
Stream流的获取方法
  • 单列集合
    • 可以使用Collection接口中的默认方法stream()生成流
    • default Stream stream()
  • 双列集合
    • 间接的生成流
    • 可以先通过keySet或者entrySet获取一个Set集合,再获取Stream流
  • 数组
    • Arrays中的静态方法stream生成流
  • 同种数据类型的多个数据
    • 使用Stream.of(T…values)生成流

示例:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.stream.Stream;

public class MyStream {
    public static void main(String[] args) {
        //单列集合
        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));

        //双列集合
        HashMap<String,Integer> hm = new HashMap<>();
        hm.put("三三",21);
        hm.put("小四",22);
        hm.put("小花",19);
        hm.put("水娃",17);
        //双列集合不能直接获取stream流
        //keySet,先获取到所有的键,再把这个Set集合中所有的键放到Stream流中
        hm.keySet().stream().forEach(s -> System.out.println(s));

        //entrySet,先获取到所有的键值对对象
        //再把这个Set集合中所有的键值对对象放到Stream流中
        hm.entrySet().stream().forEach(s -> System.out.println(s));

        //数组
        int[] arr = {1,2,3,4,5};
        Arrays.stream(arr).forEach(s -> System.out.println(s));

        //同种数据类型的多个数据
        Stream.of(1,2,3,4,5,6,7,8,9).forEach(s -> System.out.println(s));
    }
}

总结:

  • 单列集合:集合对象.stream();
  • 双列集合:不能直接获取,需要间接获取,集合对象.keySet().stream(); 集合对象.entrySet().stream();
  • 数组:Arrarys.stream(数组名);
  • 同种数据类型的多个数据:Stream.of(数据1,数据2,数据3…);
Stream流的常见中间操作方法
  • Stream filter(Predicate predicate):用于对流中的数据进行过滤
    • predicate接口中的方法
    • boolean test(T t):对给定的参数进行判断,返回一个布尔值
  • Stream limit(long maxSize):截取指定参数个数的数据
  • Stream skip(long n):跳过指定参数个数的数据
  • static Stream concat(Stream a,Stream b):合并a和b两个流为一个流
  • Stream distinct():去除流中重复的元素,依赖(hashCode和equals方法)
import java.util.ArrayList;
import java.util.stream.Stream;

/*
    过滤出张开头的字符串
 */
public class MyStream2 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("张冠李戴");
        list.add("张启山");
        list.add("张牙舞爪");
        list.add("水涨船高");
        list.add("张灯结彩");
        list.add("蒲苇纫如丝");
        list.add("磐石无转移");

        //filter方法中获取流中的每一个数据
        //而test方法中的s,就依次表示流中的数据
        //我们只要在test方法中对s进行判断就可以了
        //如果判断的结果为true,则当前数据留下
        //如果判断的结果为false,则当前数据就不要
//        list.stream().filter(new Predicate<String>() {
//            @Override
//            public boolean test(String s) {
//                boolean result = s.startsWith("张");
//                return result;
//            }
//        }).forEach(s -> System.out.println(s));

        //因为Predicate接口中只有一个抽象方法test
        //所以我们可以使用Lambda表达式来简化
//        list.stream().filter(
//                (String s) -> {
//                    boolean result = s.startsWith("张");
//                    return result;
//                }
//        ).forEach(s -> System.out.println(s));

        //简化Lambda表达式得
        list.stream().filter(s -> s.startsWith("张")).forEach(s -> System.out.println(s));

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

        //Stream<T> limit(long maxSize):截取指定参数个数的数据
        list.stream().limit(2).forEach(s -> System.out.println(s));

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

        //Stream<T> skip(long n):跳过指定参数个数的数据
        list.stream().skip(2).forEach(s -> System.out.println(s));

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

        //static <T> Stream<T> concat(Stream a,Stream b):合并a和b两个流为一个流
        ArrayList<String> list2 = new ArrayList<>();
        list2.add("张冠李戴");
        list2.add("张启山");
        list2.add("张牙舞爪");
        list2.add("水涨船高");
        list2.add("张灯结彩");
        list2.add("蒲苇纫如丝");
        list2.add("磐石无转移");
//        Stream<String> stream1 = list.stream();
//        Stream<String> stream2 = list2.stream();
//        Stream<String> stream3 = Stream.concat(stream1, stream2);
//        stream3.forEach(s -> System.out.println(s));
        Stream.concat(list.stream(),list2.stream()).forEach(s -> System.out.println(s));

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

        //Stream<T> distinct():去除流中重复的元素,依赖(hashCode和equals方法)
        list.add("张牙舞爪");
        list.stream().distinct().forEach(s -> System.out.println(s));
    }
}
Stream流的常见终结操作方法
  • void forEach(Consumer action):对此流的每个元素执行操作
    • Consumer接口中的方法
    • void accept(T t):对给定的参数执行此操作
  • long count:返回此流中的元素数
import java.util.ArrayList;

public class MyStream3 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("张冠李戴");
        list.add("张启山");
        list.add("张牙舞爪");
        list.add("水涨船高");
        list.add("张灯结彩");
        list.add("蒲苇纫如丝");
        list.add("磐石无转移");

        //在forEach方法中的底层,会循环获取到流中的每一个数据
        //并循环调用accept方法,并把每一个数据传递给accept方法
        //s就依次表示了流中的每一个数据
        //所以,我们只要在accept方法中,写上处理的业务逻辑就可以了
//        list.stream().forEach(
//                new Consumer<String>() {
//                    @Override
//                    public void accept(String s) {
//                        System.out.println(s);
//                    }
//                }
//        );
//        //Lambda表达式简化
//        list.stream().forEach(
//                (String s) -> {
//                    System.out.println(s);
//                }
//        );
        //进一步简化
        list.stream().forEach(s -> System.out.println(s));

        //long count:返回此流中的元素数
        long count = list.stream().count();
        System.out.println(count);
    }
}

运行结果:
在这里插入图片描述

Stream流的收集操作

**注:**在Stream流中无法直接修改集合,数组等数据源中的数据。

Stream流的收集方法

  • R collect(Collector collector)

工具类Collectors提供了具体的收集方式

  • public static Collector toList():把元素收集到List集合中(元素可重复)
  • public static Collector toSet():把元素收集到Set集合中(元素不可重复)
  • public static Collector toMap(Function keyMapper,Function valueMapper):把元素收集到Map集合中
  • public static Collector toMap(Function keyMapper,Function valueMapper):把元素收集到Map集合中
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/*
    定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10
    将集合中的奇数删除,只保留偶数
    遍历集合得到2,4,6,8,10
 */
public class MyStream4 {
    public static void main(String[] args) {
        ArrayList<Integer> list1 = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            list1.add(i);
        }

        //filter负责过滤数据
        //collect负责收集数据,
        // 获取流中剩余的数据,但是他不负责创建容器,也不负责把数据添加到容器中
        //Collectors.toList():在底层会创建一个List集合,并把所有的数据添加到List集合中
        List<Integer> list = list1.stream().filter(number -> number % 2 == 0).collect(Collectors.toList());
        System.out.println(list);

        Set<Integer> set = list1.stream().filter(number -> number % 2 == 0).collect(Collectors.toSet());
        System.out.println(set);
    }
}

运行结果:
在这里插入图片描述

案例

​ 现在有两个ArrayList集合,分别存储6名男角色和六名女角色,要求完成如下操作

  • 男角色只要名字为三个字的前两人
  • 女角色只要姓杨的,并且不要第一个
  • 把过滤后的男角色姓名和女角色姓名合并到一起
  • 把上一步操作后的元素作为构造方法的参数创建角色对象,遍历数据
    • 角色类Role,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法
import java.util.ArrayList;
import java.util.stream.Stream;

public class RoleTest {
    public static void main(String[] args) {
        ArrayList<String> manList = new ArrayList<>();
        manList.add("夏侯惇");
        manList.add("关羽");
        manList.add("赵云");
        manList.add("诸葛亮");
        manList.add("刘备");
        manList.add("司马懿");

        ArrayList<String> womanList = new ArrayList<>();
        womanList.add("蔡文姬");
        womanList.add("杨玉环");
        womanList.add("黄月英");
        womanList.add("施夷光");
        womanList.add("杨蓉");
        womanList.add("武曌");

        //男角色只要名字为三个字的前两人
        Stream<String> man = manList.stream().filter(name -> name.length() == 3).limit(2);
        //女角色只要姓杨的,并且不要第一个
        Stream<String> woman = womanList.stream().filter(name -> name.startsWith("杨")).skip(1);
        //把过滤后的男角色姓名和女角色姓名合并到一起
        Stream.concat(man, woman).forEach(name ->{
            Role role = new Role(name);
            System.out.println(role);
        });

    }
}

运行结果:
在这里插入图片描述

练习1

​ 定义一个方法,可以求出任意个整数的和.然后在主方法中调用.

public class Lian1 {
    public static void main(String[] args) {
        int i1 = add(3,2);
        int i2 = add(5,4,3);
        int i3 = add(6,7,8,9);
        System.out.println("两个整数的和是:"+i1);
        System.out.println("三个整数的和是:"+i2);
        System.out.println("四个整数的和是:"+i3);
    }
    public static int add(int... a){
        //此时的可变参数a可以当成数组使用
        int sum = 0;
        for(int i : a){
            sum += i;
        }
        return sum;
    }
}

运行结果:
在这里插入图片描述

练习2

​ 随机生成10个10至20之间的随机数(数字允许重复),使用Stream流的技术,找出大于15的元素并打印出来;

import java.util.ArrayList;
import java.util.Random;

public class Lian2 {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        Random r = new Random();
        for (int i = 1; i <= 10; i++) {
            int sj = r.nextInt(11)+10;
            System.out.println("第"+i+"次生成的随机数是:"+sj);
            list.add(sj);
        }
        //获取流对象,筛选数据并遍历输出
        System.out.println("大于15的元素有:");
        list.stream().filter(y->y>15).forEach(y-> System.out.print(y+" "));
    }
}

运行结果:
在这里插入图片描述

练习3

键盘录入3个学生信息,存储到学生对象(姓名,年龄).然后添加到ArrayList集合中;键盘录入3个居住地信息,添加到另一个集合ArrayList;把两个list集合中的数据收集到同一个map集合中,键是学生对对象,值是居住地址;要求map集合中不能存在相同的学生信息.并按照学生年龄降序排列;使用Stream流输出集合中所有姓张的人信息;

import java.util.ArrayList;
import java.util.Scanner;
import java.util.TreeMap;

public class StudentTest {
    public static void main(String[] args) {
        //键盘录入3个学生信息,存储到学生对象(姓名,年龄).然后添加到ArrayList集合中
        Scanner sc = new Scanner(System.in);
        ArrayList<Student> list = new ArrayList<>();
        for(int i = 1; i <= 3; i++){
            System.out.println("请输入第"+i+"个学生姓名:");
            String name = sc.next();
            System.out.println("请输入第"+i+"个学生年龄:");
            int age = sc.nextInt();
            Student st = new Student(name,age);
            list.add(st);
        }
        //键盘录入3个居住地信息,添加到另一个集合ArrayList
        ArrayList<String> listAddr = new ArrayList<>();
        for(int i = 1; i <= 3; i++){
            System.out.println("请输入第"+i+"个学生居住地:");
            String addr = sc.next();
            listAddr.add(addr);
        }
        //把两个list集合中的数据收集到同一个map集合中,键是学生对对象,值是居住地址
        //要求map集合中不能存在相同的学生信息.并按照学生年龄降序排列
        TreeMap<Student,String> tm = new TreeMap<>((s1,s2)->s2.getAge()-s1.getAge());
        for(int i = 0; i < list.size(); i++){
            Student key = list.get(i);
            String value = listAddr.get(i);
            tm.put(key,value);
        }
        //使用Stream流输出集合中所有姓张的人信息
        tm.entrySet().stream().filter(s->s.getKey().getName().startsWith("张")).forEach(s-> System.out.println("学生信息:"+s.getKey()+",对应的居住地址是:"+s.getValue()));
    }
}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值