用于简化集合和数组操作的API。
Stream流式思想的核心:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
Collections.addAll(names, "张三丰","张无忌","周芷若","赵敏","张强");
System.out.println(names);
// 使用Stream实现的
names.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));
}
}
获取Stream流
创建─条流水线,并把数据放到流水线上准备进行操作
中间方法
流水线上的操作。一次操作完毕之后,还可以继续进行其他操作
终结方法
一个Stream流只能有一个终结方法,是流水线上的最后一个操作
Stream操作集合或者数组的第一步是先得到Stream流,然后才能使用流的功能。
集合获取Stream流的方式
可以使用Collection接口中的默认方法stream()生成流
名称 | 说明 |
---|---|
default Stream< E > stream() | 获取当前集合对象的Stream流 |
数组获取Stream流的方式 |
名称 | 说明 |
---|---|
public static < T> Stream< T> stream(T[ ] array) | 获取当前数组的Stream流 |
public static< T> stream< T> of(T… values) | 获取当前数组/可变数据的Stream流 |
import java.util.*;
import java.util.stream.Stream;
public class StreamDemo02 {
public static void main(String[] args) {
/** --------------------Collection集合获取流------------------------------- */
Collection<String> list = new ArrayList<>();
Stream<String> s = list.stream();
/** --------------------Map集合获取流------------------------------- */
Map<String, Integer> maps = new HashMap<>();
// 键流
Stream<String> keyStream = maps.keySet().stream();
// 值流
Stream<Integer> valueStream = maps.values().stream();
// 键值对流(拿整体)
Stream<Map.Entry<String,Integer>> keyAndValueStream = maps.entrySet().stream();
/** ---------------------数组获取流------------------------------ */
String[] names = {"赵敏","小昭","灭绝","周芷若"};
Stream<String> nameStream = Arrays.stream(names);
Stream<String> nameStream2 = Stream.of(names);
}
}
Stream流的常用API(中间操作方法)
名称 | 说明 |
---|---|
stream< T> filter(Predicate predicate) | 用于对流中的数据进行过滤。 |
stream< T> limit(long maxsize) | 获取前几个元素 |
stream< T> skip(long n) | 跳过前几个元素 |
stream< T> distinct() | 去除流中重复的元素。依赖(hashCode和eqluals方法) |
static < T> stream< T> concat(stream a,stream b) | 合并a和b两个流为一个流 |
注意: |
Stream流的常见终结操作方法
名称 | 说明 |
---|---|
void forEach(Consumer action) | 对此流的每个元素执行遍历操作 |
long count() | 返回此流中的元素数 |
注意:终结操作方法,调用完成后流就无法继续使用了,原因是不会返回Stream了。 |
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class StreamDemo03 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张三丰");
// Stream filter(Predicate predicate)
list.stream().filter(s -> s.startsWith("张")).forEach(s -> System.out.println(s));
long size = list.stream().filter(s -> s.length() == 3).count();
System.out.println(size);
// list.stream().filter(s -> s.startsWith("张")).limit(2).forEach(s -> System.out.println(s));
list.stream().filter(s -> s.startsWith("张")).limit(2).forEach(System.out::println);
list.stream().filter(s -> s.startsWith("张")).skip(2).forEach(System.out::println);
// map加工方法: 第一个参数原材料 -> 第二个参数是加工后的结果。
// 给集合元素的前面都加上一个:黑马的:
list.stream().map(s -> "黑马的:" + s).forEach(a -> System.out.println(a));
// 需求:把所有的名称 都加工成一个学生对象。
list.stream().map(s -> new Student(s)).forEach(s -> System.out.println(s));
// list.stream().map(Student::new).forEach(System.out::println); // 构造器引用 方法引用
// 合并流。
Stream<String> s1 = list.stream().filter(s -> s.startsWith("张"));
Stream<String> s2 = Stream.of("java1", "java2");
// public static Stream concat(Stream a, Stream b)
Stream<String> s3 = Stream.concat(s1 , s2);
s3.distinct().forEach(s -> System.out.println(s));
}
}
收集Stream流的含义:就是把Stream流操作后的结果数据转回到集合或者数组中去。
Stream流:方便操作集合/数组的手段。
集合/数组:才是开发中的目的。
Stream流的收集方法
名称 | 说明 |
---|---|
R collect(collector collector) | 开始收集Stream流,指定收集器 |
Collectors工具类提供了具体的收集方式 | |
名称 | 说明 |
:-: | :-: |
public static Collector toList() | 把元素收集到List集合中 |
public static collector toSet() | 把元素收集到Set集合中 |
public static collector toMap(Function keyMapper , Function valueMapper) | 把元素收集到Map集合中 |
import java.util.*;
import java.util.function.IntFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamDemo05 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张三丰");
Stream<String> s1 = list.stream().filter(s -> s.startsWith("张"));
List<String> zhangList = s1.collect(Collectors.toList()); // 可变集合
zhangList.add("java1");
System.out.println(zhangList);
// 注意注意注意:“流只能使用一次”
Stream<String> s2 = list.stream().filter(s -> s.startsWith("张"));
Set<String> zhangSet = s2.collect(Collectors.toSet());
System.out.println(zhangSet);
Stream<String> s3 = list.stream().filter(s -> s.startsWith("张"));
// Object[] arrs = s3.toArray();
String[] arrs = s3.toArray(String[]::new); // 可以不管,拓展一下思维!!
System.out.println("Arrays数组内容:" + Arrays.toString(arrs));
}
}
异常是程序在"编译"或者"执行"的过程中可能出现的问题,注意:语法错误不算在异常体系中。比如:数组索引越界、空指针异常、日期格式化异常,等…
异常一旦出现了,如果没有提前处理,程序就会退出JVM虚拟机而终止。研究异常并且避免异常,然后提前处理异常,体现的是程序的安全,健壮性。
Exception: java.lang包下,称为异常类,它表示程序本身可以处理的问题
== RuntimeException及其子类:运行时异常,编译阶段不会报错。(空指针异常,数组索引越界异常)==
== 除RuntimeException之外所有的异常:编译时异常,编译期必须处理的,否则程序不能通过编译。(日期格式化异常)。==
编译时异常就是在编译的时候出现的异常,运行时异常就是在运行时出现的异常。
直接继承自RuntimeException或者其子类,编译阶段不会报错,运行时可能出现的错误。
运行时异常示例
中文 | 英文 |
---|---|
数组索引越界异常 | ArraylndexOutOfBoundsException |
空指针异常 | NullPointerException,直接输出没有问题,但是调用空指针H的变量的 |
数学操作异常 | ArithmeticException |
类型转换异常 | ClassCastException |
数字转换异常 | NumberFormatException |
运行时异常:一般是程序员业务没有考虑好或者是编程逻辑不严谨引起的程序错误,自己的水平有问题!
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("程序开始。。。。。。");
/** 1.数组索引越界异常: ArrayIndexOutOfBoundsException。*/
int[] arr = {1, 2, 3};
System.out.println(arr[2]);
// System.out.println(arr[3]); // 运行出错,程序终止
/** 2.空指针异常 : NullPointerException。直接输出没有问题。但是调用空指针的变量的功能就会报错!! */
String name = null;
System.out.println(name); // null
// System.out.println(name.length()); // 运行出错,程序终止
/** 3.类型转换异常:ClassCastException。 */
Object o = 23;
// String s = (String) o; // 运行出错,程序终止
/** 5.数学操作异常:ArithmeticException。 */
//int c = 10 / 0;
/** 6.数字转换异常: NumberFormatException。 */
//String number = "23";
String number = "23aabbc";
Integer it = Integer.valueOf(number); // 运行出错,程序终止
System.out.println(it + 1);
System.out.println("程序结束。。。。。");
}
}
不是RuntimeException或者其子类的异常,编译阶段就报错,必须处理,否则代码不通过。
编译时异常的作用是担心程序员的技术不行,在编译阶段就爆出一个错误,目的在于提醒不要出错!编译时异常是可遇不可求。遇到了就遇到了呗。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo {
public static void main(String[] args) throws ParseException {
String date = "2015-01-12 10:23:21";
// 创建一个简单日期格式化类:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM-dd HH:mm:ss");
// 解析字符串时间成为日期对象
Date d = sdf.parse(date);
//
System.out.println(d);
}
}
编译时异常是编译阶段就出错的,所以必须处理,否则代码根本无法通过。
编译时异常的处理形式有三种:
异常处理方式1——throws
throws:用在方法上,可以将方法内部出现的异常抛出去给本方法的调用者处理。
这种方式并不好,发生异常的方法自己不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡。
//抛出异常格式
方法 throws 异常1,异常2,异常3..{
}
//规范做法
方法 throws Exception{
}
//(代表可以抛出一切异常)
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo01 {
public static void main(String[] args) throws Exception {
System.out.println("程序开始。。。。。");
parseTime("2011-11-11 11:11:11");
System.out.println("程序结束。。。。。");
}
public static void parseTime(String date) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
}
}
异常处理方式2—— try…catch…
监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理。
这种方式还可以,发生异常的方法自己独立完成异常的处理,程序可以继续往下执行。
//格式:
try{
//监视可能出现异常的代码!
}catch(异常类型1变量){
//处理异常
}catch(异常类型2变量){
//处理异常
}...
//建议格式:
try{
//可能出现异常的代码!
}catch(Exception e){
e.printStackTrace();
}
//Exception可以捕获一切异常类型
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo02 {
public static void main(String[] args) {
System.out.println("程序开始。。。。");
parseTime("2011-11-11 11:11:11");
System.out.println("程序结束。。。。");
}
public static void parseTime(String date) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
InputStream is = new FileInputStream("E:/meinv.jpg");
} catch (Exception e) {
e.printStackTrace(); // 打印异常栈信息
}
}
}
异常处理方式3——前两者结合
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo03 {
public static void main(String[] args) {
System.out.println("程序开始。。。。");
try {
parseTime("2011-11-11 11:11:11");
System.out.println("功能操作成功~~~");
} catch (Exception e) {
e.printStackTrace();
System.out.println("功能操作失败~~~");
}
System.out.println("程序结束。。。。");
}
public static void parseTime(String date) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy、MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
InputStream is = new FileInputStream("D:/meinv.jpg");
}
}
在开发中按照规范来说第三种方式是最好的:底层的异常抛出去给最外层,最外层集中捕获处理。
实际应用中,只要代码能够编译通过,并且功能能完成,那么每一种异常处理方式似乎也都是可以的。
运行时异常编译阶段不会出错,是运行时才可能出错的,所以编译阶段不处理也可以。
按照规范建议还是处理:建议在最外层调用处集中捕获处理即可。
自定义异常的必要?
自定义异常的好处:
自定义异常的分类
1、自定义编译时异常
作用:编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理!!
2、自定义运行时异常
作用:提醒不强烈,编译阶段不报错!!运行时才可能出现!!
/**
自定义的编译时异常
1、继承Exception
2、重写构造器
*/
public class ItheimaAgeIlleagalException extends Exception{
public ItheimaAgeIlleagalException() {
}
public ItheimaAgeIlleagalException(String message) {
super(message);
}
}
/**
自定义的编译时异常
1、继承RuntimeException
2、重写构造器
*/
public class ItheimaAgeIlleagalRuntimeException extends RuntimeException{
public ItheimaAgeIlleagalRuntimeException() {
}
public ItheimaAgeIlleagalRuntimeException(String message) {
super(message);
}
}
public class ExceptionDemo {
public static void main(String[] args) {
try {
checkAge2(-23);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void checkAge2(int age) {
if(age < 0 || age > 200){
// 抛出去一个异常对象给调用者
// throw :在方法内部直接创建一个异常对象,并从此点抛出
// throws : 用在方法申明上的,抛出方法内部的异常
throw new ItheimaAgeIlleagalRuntimeException(age + " is illeagal!");
}else {
System.out.println("年龄合法:推荐商品给其购买~~");
}
}
public static void checkAge(int age) throws ItheimaAgeIlleagalException {
if(age < 0 || age > 200){
// 抛出去一个异常对象给调用者
// throw :在方法内部直接创建一个异常对象,并从此点抛出
// throws : 用在方法申明上的,抛出方法内部的异常
throw new ItheimaAgeIlleagalException(age + " is illeagal!");
}else {
System.out.println("年龄合法:推荐商品给其购买~~");
}
}
}