Java程序设计--Stream流、异常(十四)


1、Stream流

1.1 Stream流的概述

用于简化集合和数组操作的API。

Stream流式思想的核心:

  1. 先得到集合或者数组的Stream流(就是一根传送带)
  2. 把元素放上去
  3. 然后就用这个Stream流简化的API来方便的操作元素。
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));
    }
}

1.2 Stream流的获取

获取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);
    }
}

1.3 Stream流的常用API

Stream流的常用API(中间操作方法)

名称说明
stream< T> filter(Predicate<? super T> 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流可以继续使用,支持链式编程。
  • 在Stream流中无法直接修改集合、数组中的数据。

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<T> filter(Predicate<? super T> 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 <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
        Stream<String> s3 = Stream.concat(s1 , s2);
        s3.distinct().forEach(s -> System.out.println(s));
    }
}

1.4 Stream流的收集操作

  • 收集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));

    }
}

2、异常处理

2.1 异常概述

异常是程序在"编译"或者"执行"的过程中可能出现的问题,注意:语法错误不算在异常体系中。比如:数组索引越界、空指针异常、日期格式化异常,等…

异常一旦出现了,如果没有提前处理,程序就会退出JVM虚拟机而终止。研究异常并且避免异常,然后提前处理异常,体现的是程序的安全,健壮性。

在这里插入图片描述
Error:

  • 系统级别问题、JVM退出等,代码无法控制。

Exception: java.lang包下,称为异常类,它表示程序本身可以处理的问题

  • == RuntimeException及其子类:运行时异常,编译阶段不会报错。(空指针异常,数组索引越界异常)==

  • == 除RuntimeException之外所有的异常:编译时异常,编译期必须处理的,否则程序不能通过编译。(日期格式化异常)。==

在这里插入图片描述

编译时异常就是在编译的时候出现的异常,运行时异常就是在运行时出现的异常。

2.2 常见运行时异常

直接继承自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("程序结束。。。。。");
    }
}

2.3 常见编译时异常

不是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);
    }
}

2.4 异常默认处理机制

  1. 默认会在出现异常的代码那里自动的创建一个异常对象:ArithmeticException。
  2. 异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机。
  3. 虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据。
  4. 直接从当前执行的异常点干掉当前程序。
  5. 后续代码没有机会执行了,因为程序已经死亡。

2.5 编译时异常的处理机制

编译时异常是编译阶段就出错的,所以必须处理,否则代码根本无法通过。

编译时异常的处理形式有三种:

  1. 出现异常直接抛出去给调用者,调用者也继续抛出去。
  2. 出现异常自己捕获处理,不麻烦别人。
  3. 前两者结合,出现异常直接抛出去给调用者,调用者捕获处理。

异常处理方式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——前两者结合

  • 方法直接将异通过throws抛出去给调用者
  • 调用者收到异常后直接捕获处理
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");
    }

}

在开发中按照规范来说第三种方式是最好的:底层的异常抛出去给最外层,最外层集中捕获处理。

实际应用中,只要代码能够编译通过,并且功能能完成,那么每一种异常处理方式似乎也都是可以的。

2.6 运行时异常的处理机制

运行时异常编译阶段不会出错,是运行时才可能出错的,所以编译阶段不处理也可以。

按照规范建议还是处理:建议在最外层调用处集中捕获处理即可。

2.7 自定义异常

自定义异常的必要?

  • Java无法为这个世界上全部的问题提供异常类。
  • 如果企业想通过异常的方式来管理自己的某个业务问题,就需要自定义异常类了。

自定义异常的好处:

  • 可以使用异常的机制管理业务问题,如提醒程序员注意。
  • 同时一旦出现bug,可以用异常的形式清晰的指出出错的地方。

自定义异常的分类

1、自定义编译时异常

  1. 定义一个异常类继承Exception
  2. 重写构造器
  3. 在出现异常的地方用throw new自定义对象抛出

作用:编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理!!

2、自定义运行时异常

  1. 定义一个异常类继承RuntimeException
  2. 重写构造器
  3. 在出现异常的地方用throw new自定义对象抛出

作用:提醒不强烈,编译阶段不报错!!运行时才可能出现!!

/**
    自定义的编译时异常
      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("年龄合法:推荐商品给其购买~~");
        }
    }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会思想的苇草i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值