一、Stream流引入
Lambda表达式,基于Lambda所带来的函数式编程,又引入了一个全新的Stream概念,用于解决集合类库既有的鼻端。
现有一个需求:
将list集合中姓张的元素过滤到一个新的集合中
然后将过滤出来的姓张的元素中,再过滤出来长度为3的元素,存储到一个新的集合中
1.用常规方法解决需求
// 已知的知识来解决需求List<String> list1 = new ArrayList<>();list1.add("张老三");list1.add("张小三");list1.add("李四");list1.add("赵五");list1.add("张六");list1.add("王八");ArrayList<String> list2 = new ArrayList<>();// 1.将list集合中姓张的元素过滤到一个新的集合中for(String name : list1){if(name.startsWith("张")){list2.add(name);}}ArrayList list3 = new ArrayList();for (String name : list2) {if (name.length() == 3){list3.add(name);}}System.out.println(list3);输出结果:[张老三, 张小三]
2.用Stream流操作集合,获取流,过滤操作,打印输出
list1.stream().filter(name->name.startsWith("张")).filter(name->name.length()==3).forEach(name->System.out.println("符合条件的姓名:" + name));
二、Stream流的格式
Stream<T> filter(Predicate<? super T> predicate);-----> 参数:public interface Predicate<T> (函数式接口)----> 抽象方法:boolean test(T t);-----> 参数:public interface Consumer<T> (函数式接口)----> 抽象方法:boolean test(T t);
三、获取流
根据集合来获取:
根据Collection获取流:
Collection接口中有一个stream()方法,可以获取流**default Stream<E> stream()**
- 根据List获取流
- 根据Set获取流
- 根据Map获取流
- 根据Map集合的键来获取流
- 根据Map集合的值获取流
- 根据Map集合的键值对对象获取流
-
代码演示:
1.根据List集合获取流
// 创建List集合List<String> list = new ArrayList<>();list.add("张老三");list.add("张小三");list.add("李四");list.add("赵五");list.add("张六");list.add("王八");Stream<String> stream1 = list.stream();
2.根据Set集合获取流
// 创建List集合Set<String> set = new HashSet<>();list.add("张老三");list.add("张小三");list.add("李四");list.add("赵五");list.add("张六");list.add("王八");Stream<String> stream2 = set.stream();
3.根据Map集合获取流
// 创建Map集合Map<Integer,String> map = new HashMap<>();map.put(1,"张老三");map.put(2,"张小三");map.put(3,"李四");map.put(4,"赵五");map.put(5,"张六");map.put(6,"王八");// 3.1根据Map集合的键获取流Set<Integer> map1 = map.keySet();Stream<Integer> stream3 = map1.stream();// 3.2根据Map集合的值获取流Collection<String> map2 = map.values();Stream<String> stream4 = map2.stream();// 3.3根据Map集合的键值对对象获取瑞Set<Map.Entry<Integer, String>> map3 = map.entrySet();Stream<Map.Entry<Integer, String>> stream5 = map3.stream();
4.根据数组获取流
// 根据数组获取流String[] arr = {"张颜宇","张三","李四","赵五","刘六","王七"};Stream<String> stream6 = Stream.of(arr);
四、Stream流的常用方法
Stream流的常用方法:
终结方法:返回值类型不再是Stream接口本身类型的方法,例如:forEach方法和count方法
非终结方法/延迟方法:返回值类型仍然是Stream接口自身类型的方法,除了终结方法都是延迟方法。例如:filter,limit,skip,map,conat
| 方法名称 | 方法作用 | 方法种类 | 是否支持链式调用 |
|---|---|---|---|
| count | 统计个数 | 终结方法 | 否 |
| forEach | 逐一处理 | 终结方法 | 否 |
| filter | 过滤 | 函数拼接 | 是 |
| limit | 取用前几个 | 函数拼接 | 是 |
| skip | 跳过前几个 | 函数拼接 | 是 |
| map | 映射 | 函数拼接 | 是 |
| concat | 组合 | 函数拼接 | 是 |
方法演示:
1.count方法:
long count (); 统计流中的元素,返回long类型数据
List<String> list = new ArrayList<>();list.add("张老三");list.add("张小三");list.add("李四");list.add("赵五");list.add("张六");list.add("王八");long count = list.stream().count();System.out.println("集合中的元素个数是:" + count);输出结果:集合中的元素个数是:6
2.filter方法:
Stream
参数Predicate:函数式接口,抽象方法:boolean test (T t)
Predicate接口:是一个判断接口
// 获取stream流Stream<String> stream = Stream.of("张老三", "张小三", "李四", "赵五", "刘六", "王七");// 需求:过去出姓张的元素stream.filter((String name)->{return name.startsWith("张");}).forEach((String name)->{System.out.println("流中的元素" + name);});
3.forEach方法
void forEach(Consumer<? super T> action):逐一处理流中的元素
参数 Consumer<? super T> action:函数式接口,只有一个抽象方法:void accept(T t);
注意:
1.此方法并不保证元素的逐一消费动作在流中是有序进行的(元素可能丢失)
2.Consumer是一个消费接口(可以获取流中的元素进行遍历操作,输出出去),可以使用Lambda表达式
List<String> list = new ArrayList<>();list.add("张老三");list.add("张小三");list.add("李四");list.add("赵五");list.add("张六");list.add("王八");// 函数模型:获取流 --> 注意消费流中的元素list.stream().forEach(name->System.out.println(name));输出结果:张老三张小三李四赵五张六王八
4.limit方法
Stream
注意:
参数是一个long 类型,如果流的长度大于参数,则进行截取;否则不进行操作
// 获取流的长度Stream<String> stream1 = Stream.of("张老三", "张小三", "李四", "赵五", "刘六", "王七");// 需求:保留前三个元素stream1.limit(3).forEach((String name)->{System.out.println("流中的前三个元素是:" + name);});输出结果:流中的前三个元素是:张老三流中的前三个元素是:张小三流中的前三个元素是:李四
5.map方法
参数Function
Function
// 获取Stream流Stream<String> stream1 = Stream.of("11","22","33","44","55");// 需求:把stream1流中的元素转换为int类型stream1.map(s->Integer.parseInt(s)// 将String类型的s进行转换为Integer类型的元素,并返回).forEach(i->System.out.println(i) // 将转换后的int类型的元素逐一输出);输出结果:1122334455
6.skip方法
Stream
注意:
如果流的当前长度大于n,则跳过前n个,否则将会得到一个长度为0的空流
// 获取stream流Stream<String> stream = Stream.of("张老三", "张小三", "李四", "赵五", "刘六", "王七");stream.skip(3).forEach(name->System.out.println("跳过前三个,打印剩下的" + name));输出结果:跳过前三个,打印剩下的赵五跳过前三个,打印剩下的刘六跳过前三个,打印剩下的王七
7.concat方法
public static
—> 合并两个流
Stream<String> stream1 = Stream.of("11","22","33","44","55");Stream<String> stream2 = Stream.of("张颜宇", "张三", "李四", "赵五", "刘六", "王七");// 需求:合并两个流Stream<String> stream = Stream.concat(stream1,stream2);stream.forEach( name->System.out.print(name));输出结果:1122334455张颜宇张三李四赵五刘六王七
五、收集Stream流
Stream流中提供了一个方法,可以把流中的数据收集到单例集合中
返回值类型是R。R指定为什么类型,就是手机到什么类型的集合
参数Collector<? super T, A, R>中的R类型,决定把流中的元素收集到哪个集合中
参数Collector如何得到 ?,可以使用 java.util.stream.Collectors工具类中的静态方法:
- public static
- public static
List<String> list2 = new ArrayList<>();list2.add("张老三");list2.add("张小三");list2.add("李四");list2.add("赵五");list2.add("张六");list2.add("王八");// 需求:过滤出姓张的并且长度为3的元素Stream<String> stream = list2.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3);// stream 收集到单列集合中List<String> list = stream.collect(Collectors.toList());System.out.println(list);// stream 手机到单列集合中Set<String> set = stream.collect(Collectors.toSet());System.out.println(set);
六、异常
在 Java 中一个异常的产生,主要有如下三种原因:
- Java 内部错误发生异常,Java 虚拟机产生的异常。
- 编写的程序代码中的错误所产生的异常,例如空指针异常、数组越界异常等。
- 通过 throw 语句手动生成的异常,一般用来告知该方法的调用者一些必要信息。
- Java 通过面向对象的方法来处理异常。在一个方法的运行过程中,如果发生了异常,则这个方法会产生代表该异常的一个对象,并把它交给运行时的系统,运行时系统寻找相应的代码来处理这一异常
- 我们把生成异常对象,并把它提交给运行时系统的过程称为拋出(throw)异常。运行时系统在方法的调用栈中查找,直到找到能够处理该类型异常的对象,这一个过程称为捕获(catch)异常。
- 运行时异常都是 RuntimeException 类及其子类异常,如 NullPointerException、IndexOutOfBoundsException 等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般由程序逻辑错误引起,程序应该从逻辑角度尽可能避免这类异常的发生。
- 非运行时异常是指 RuntimeException 以外的异常,类型上都属于 Exception 类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如 IOException、ClassNotFoundException 等以及用户自定义的 Exception 异常(一般情况下不自定义检查异常)。
运行时异常
| 异常类型 | 说明 |
|---|---|
| ArithmeticException | 算术错误异常,如以零做除数 |
| ArraylndexOutOfBoundException | 数组索引越界 |
| ArrayStoreException | 向类型不兼容的数组元素赋值 |
| ClassCastException | 类型转换异常 |
| IllegalArgumentException | 使用非法实参调用方法 |
| lIIegalStateException | 环境或应用程序处于不正确的状态 |
| lIIegalThreadStateException | 被请求的操作与当前线程状态不兼容 |
| IndexOutOfBoundsException | 某种类型的索引越界 |
| NullPointerException | 尝试访问 null 对象成员,空指针异常 |
| NegativeArraySizeException | 再负数范围内创建的数组 |
| NumberFormatException | 数字转化格式异常,比如字符串到 float 型数字的转换无效 |
| TypeNotPresentException | 类型未找到 |
非运行时异常
| 异常类型 | 说明 |
|---|---|
| ClassNotFoundException | 没有找到类 |
| IllegalAccessException | 访问类被拒绝 |
| InstantiationException | 试图创建抽象类或接口的对象 |
| InterruptedException | 线程被另一个线程中断 |
| NoSuchFieldException | 请求的域不存在 |
| NoSuchMethodException | 请求的方法不存在 |
| ReflectiveOperationException | 与反射有关的异常的超类 |
