Java 入门 39 不可变集合对象 Stream 流 认知异常体系 日志框架
package com.itheima.d1_unchange_collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** 目标:不可变集合。 */ public class CollectionDemo { public static void main(String[] args) { // 1、不可变的List集合 List<Double> lists = List.of(569.5, 700.5, 523.0, 570.5); // lists.add(689.0); // lists.set(2, 698.5); // System.out.println(lists); double score = lists.get(1); System.out.println(score); // 2、不可变的Set集合 Set<String> names = Set.of("迪丽热巴", "迪丽热九", "马尔扎哈", "卡尔眨巴" ); // names.add("三少爷"); System.out.println(names); // 3、不可变的Map集合 Map<String, Integer> maps = Map.of("huawei",2, "Java开发", 1 , "手表", 1); // maps.put("衣服", 3); System.out.println(maps); } }
Stream流
package com.itheima.d2_stream; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** 目标:初步体验Stream流的方便与快捷 */ public class StreamTest { public static void main(String[] args) { List<String> names = new ArrayList<>(); Collections.addAll(names, "张三丰","张无忌","周芷若","赵敏","张强"); System.out.println(names); // // // 1、从集合中找出姓张的放到新集合 // List<String> zhangList = new ArrayList<>(); // for (String name : names) { // if(name.startsWith("张")){ // zhangList.add(name); // } // } // System.out.println(zhangList); // // // 2、找名称长度是3的姓名 // List<String> zhangThreeList = new ArrayList<>(); // for (String name : zhangList) { // if(name.length() == 3){ // zhangThreeList.add(name); // } // } // System.out.println(zhangThreeList); // 3、使用Stream实现的 names.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s)); } }
Stream流获取
package com.itheima.d2_stream; import java.util.*; import java.util.stream.Stream; /** 目标:Stream流的获取 Stream流式思想的核心: 是先得到集合或者数组的Stream流(就是一根传送带) 然后就用这个Stream流操作集合或者数组的元素。 然后用Stream流简化替代集合操作的API. 集合获取流的API: (1) default Stream<E> stream(); 小结: 集合获取Stream流用: stream(); 数组:Arrays.stream(数组) / Stream.of(数组); */ 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
Student类
package com.itheima.d2_stream; public class Student { private String name; public Student() { } public Student(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + '}'; } }
测试类
package com.itheima.d2_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; /** 目标:Stream流的常用API forEach : 逐一处理(遍历) count:统计个数 -- long count(); filter : 过滤元素 -- Stream<T> filter(Predicate<? super T> predicate) limit : 取前几个元素 skip : 跳过前几个 map : 加工方法 concat : 合并流。 */ 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)); } }
Stream流常见终结操作API
案例
Topperformer类
package com.itheima.d2_stream; public class Topperformer { private String name; private double money; // 月薪 public Topperformer() { } public Topperformer(String name, double money) { this.name = name; this.money = money; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } @Override public String toString() { return "Topperformer{" + "name='" + name + '\'' + ", money=" + money + '}'; } }
测试类
package com.itheima.d2_stream; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class StreamDemo04 { public static double allMoney ; public static double allMoney2 ; // 2个部门去掉最高工资,最低工资的总和 public static void main(String[] args) { List<Employee> one = new ArrayList<>(); one.add(new Employee("猪八戒",'男',30000 , 25000, null)); one.add(new Employee("孙悟空",'男',25000 , 1000, "顶撞上司")); one.add(new Employee("沙僧",'男',20000 , 20000, null)); one.add(new Employee("小白龙",'男',20000 , 25000, null)); List<Employee> two = new ArrayList<>(); two.add(new Employee("武松",'男',15000 , 9000, null)); two.add(new Employee("李逵",'男',20000 , 10000, null)); two.add(new Employee("西门庆",'男',50000 , 100000, "被打")); two.add(new Employee("潘金莲",'女',3500 , 1000, "被打")); two.add(new Employee("武大郎",'女',20000 , 0, "下毒")); // 1、开发一部的最高工资的员工。(API) // 指定大小规则了 // Employee e = one.stream().max((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(), e2.getSalary() + e2.getBonus())) // .get(); // System.out.println(e); Topperformer t = one.stream().max((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(), e2.getSalary() + e2.getBonus())) .map(e -> new Topperformer(e.getName(), e.getSalary() + e.getBonus())).get(); System.out.println(t); // 2、统计平均工资,去掉最高工资和最低工资 one.stream().sorted((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(), e2.getSalary() + e2.getBonus())) .skip(1).limit(one.size() - 2).forEach(e -> { // 求出总和:剩余员工的工资总和 allMoney += (e.getSalary() + e.getBonus()); }); System.out.println("开发一部的平均工资是:" + allMoney / (one.size() - 2)); // 3、合并2个集合流,再统计 Stream<Employee> s1 = one.stream(); Stream<Employee> s2 = two.stream(); Stream<Employee> s3 = Stream.concat(s1 , s2); s3.sorted((e1, e2) -> Double.compare(e1.getSalary() + e1.getBonus(), e2.getSalary() + e2.getBonus())) .skip(1).limit(one.size() + two.size() - 2).forEach(e -> { // 求出总和:剩余员工的工资总和 allMoney2 += (e.getSalary() + e.getBonus()); }); // BigDecimal BigDecimal a = BigDecimal.valueOf(allMoney2); BigDecimal b = BigDecimal.valueOf(one.size() + two.size() - 2); System.out.println("开发部的平均工资是:" + a.divide(b,2, RoundingMode.HALF_UP)); } }
Stream流的收集操作
package com.itheima.d2_stream; import java.util.*; import java.util.function.IntFunction; import java.util.stream.Collectors; import java.util.stream.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); // List<String> list1 = s1.toList(); // 得到不可变集合 // list1.add("java"); // System.out.println(list1); // 注意注意注意:“流只能使用一次” 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)); } }
异常体系
package com.itheima.d3_exception; /** 目标:异常的概念和体系。 什么是异常? 异常是程序在"编译"或者"执行"的过程中可能出现的问题。 异常是应该尽量提前避免的。 异常可能也是无法做到绝对避免的,异常可能有太多情况了,开发中只能提前干预!! 异常一旦出现了,如果没有提前处理,程序就会退出JVM虚拟机而终止,开发中异常是需要提前处理的。 研究异常并且避免异常,然后提前处理异常,体现的是程序的安全, 健壮性!!! Java会为常见的代码异常都设计一个类来代表。 异常的体系: Java中异常继承的根类是:Throwable。 Throwable(根类,不是异常类) / \ Error Exception(异常,需要研究和处理) / \ 编译时异常 RuntimeException(运行时异常) Error : 错误的意思,严重错误Error,无法通过处理的错误,一旦出现,程序员无能为力了, 只能重启系统,优化项目。 比如内存奔溃,JVM本身的奔溃。这个程序员无需理会。 Exception:才是异常类,它才是开发中代码在编译或者执行的过程中可能出现的错误, 它是需要提前处理的。以便程序更健壮! Exception异常的分类: 1.编译时异常:继承自Exception的异常或者其子类,编译阶段就会报错, 必须程序员处理的。否则代码编译就不能通过!! 2.运行时异常: 继承自RuntimeException的异常或者其子类,编译阶段是不会出错的,它是在 运行时阶段可能出现,运行时异常可以处理也可以不处理,编译阶段是不会出错的, 但是运行阶段可能出现,还是建议提前处理!! 小结: 异常是程序在编译或者运行的过程中可能出现的错误!! 异常分为2类:编译时异常,运行时异常。 -- 编译时异常:继承了Exception,编译阶段就报错,必须处理,否则代码不通过。 -- 运行时异常:继承了RuntimeException,编译阶段不会报错,运行时才可能出现。 异常一旦真的出现,程序会终止,所以要研究异常,避免异常,处理异常,程序更健壮!! */ public class ExceptionDemo { public static void main(String[] args) { int[] arr = {10, 20, 40}; System.out.println(arr[0]); System.out.println(arr[1]); System.out.println(arr[2]); System.out.println(arr[3]); System.out.println("-----------程序截止---------"); } }
运行时异常
异常的默认处理流程
package com.itheima.d6_exception_default; /** 目标:异常的产生默认的处理过程解析。(自动处理的过程!) (1)默认会在出现异常的代码那里自动的创建一个异常对象:ArithmeticException。 (2)异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机。 (3)虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据。 (4)直接从当前执行的异常点干掉当前程序。 (5)后续代码没有机会执行了,因为程序已经死亡。 小结: 异常一旦出现,会自动创建异常对象,最终抛出给虚拟机,虚拟机 只要收到异常,就直接输出异常信息,干掉程序!! 默认的异常处理机制并不好,一旦真的出现异常,程序立即死亡! */ public class ExceptionDemo { public static void main(String[] args) { System.out.println("程序开始。。。。。。。。。。"); chu(10, 0); System.out.println("程序结束。。。。。。。。。。"); } public static void chu(int a , int b){ System.out.println(a); System.out.println(b); int c = a / b; System.out.println(c); } }
编译时处理异常的三种方式
异常处理方式1----throws
package com.itheima.d7_exception_handle; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** 目标:编译时异常的处理方式一。 编译时异常:编译阶段就会报错,一定需要程序员处理的,否则代码无法通过!! 抛出异常格式: 方法 throws 异常1 , 异常2 , ..{ } 建议抛出异常的方式:代表可以抛出一切异常, 方法 throws Exception{ } 方式一: 在出现编译时异常的地方层层把异常抛出去给调用者,调用者最终抛出给JVM虚拟机。 JVM虚拟机输出异常信息,直接干掉程序,这种方式与默认方式是一样的。 虽然可以解决代码编译时的错误,但是一旦运行时真的出现异常,程序还是会立即死亡! 这种方式并不好! 小结: 方式一出现异常层层跑出给虚拟机,最终程序如果真的出现异常,程序还是立即死亡!这种方式不好! */ public class ExceptionDemo01 { // public static void main(String[] args) throws ParseException, FileNotFoundException { // System.out.println("程序开始。。。。。"); // parseTime("2011-11-11 11:11:11"); // System.out.println("程序结束。。。。。"); // } // // public static void parseTime(String date) throws ParseException, FileNotFoundException { // 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"); // } 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); InputStream is = new FileInputStream("E:/meinv.jpg"); } }
异常处理方式2 try{}catch(){}
package com.itheima.d7_exception_handle; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** 目标:编译时异常的处理方式二。 方式二:在出现异常的地方自己处理,谁出现谁处理。 自己捕获异常和处理异常的格式:捕获处理 try{ // 监视可能出现异常的代码! }catch(异常类型1 变量){ // 处理异常 }catch(异常类型2 变量){ // 处理异常 }... 监视捕获处理异常企业级写法: try{ // 可能出现异常的代码! }catch (Exception e){ e.printStackTrace(); // 直接打印异常栈信息 } Exception可以捕获处理一切异常类型! 小结: 第二种方式,可以处理异常,并且出现异常后代码也不会死亡。 这种方案还是可以的。 但是从理论上来说,这种方式不是最好的,上层调用者不能直接知道底层的执行情况! */ 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(); // 打印异常栈信息 } } // 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 (FileNotFoundException|ParseException e) { // e.printStackTrace(); // 打印异常栈信息 // } // } // 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 (FileNotFoundException e) { // e.printStackTrace(); // 打印异常栈信息 // } catch (ParseException e) { // e.printStackTrace(); // } // } // 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); // } catch (ParseException e) { // // 解析出现问题 // System.out.println("出现了解析时间异常哦,走点心!!"); // } // // try { // InputStream is = new FileInputStream("E:/meinv.jpg"); // } catch (FileNotFoundException e) { // System.out.println("您的文件根本就没有啊,不要骗我哦!!"); // } // } }
异常处理方式3 前两者结合
package com.itheima.d7_exception_handle; 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"); } }
异常处理使代码更稳健的案例
Test2
package com.itheima.d8_exception_handle_runtime; import java.util.Scanner; /** 需求:需要输入一个合法的价格为止 要求价格大于 0 */ public class Test2 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (true) { try { System.out.println("请您输入合法的价格:"); String priceStr = sc.nextLine(); // 转换成double类型的价格 double price = Double.valueOf(priceStr); // 判断价格是否大于 0 if(price > 0) { System.out.println("定价:" + price); break; }else { System.out.println("价格必须是正数~~~"); } } catch (Exception e) { System.out.println("用户输入的数据有毛病,请您输入合法的数值,建议为正数~~"); } } } }
Test测试
package com.itheima.d8_exception_handle_runtime; /** 目标:运行时异常的处理机制。 可以不处理,编译阶段又不报错。 按照理论规则:建议还是处理,只需要在最外层捕获处理即可 */ public class Test { public static void main(String[] args) { System.out.println("程序开始。。。。。。。。。。"); try { chu(10, 0); } catch (Exception e) { e.printStackTrace(); } System.out.println("程序结束。。。。。。。。。。"); } public static void chu(int a , int b) { // throws RuntimeException{ System.out.println(a); System.out.println(b); int c = a / b; System.out.println(c); } }
自定义异常
自定义异常的分类
ExceptionDemo
package com.itheima.d9_exception_custom; /** 目标:自定义异常(了解) 引入:Java已经为开发中可能出现的异常都设计了一个类来代表. 但是实际开发中,异常可能有无数种情况,Java无法为 这个世界上所有的异常都定义一个代表类。 假如一个企业如果想为自己认为的某种业务问题定义成一个异常 就需要自己来自定义异常类. 需求:认为年龄小于0岁,大于200岁就是一个异常。 自定义异常: 自定义编译时异常. a.定义一个异常类继承Exception. b.重写构造器。 c.在出现异常的地方用throw new 自定义对象抛出! 编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理!! 自定义运行时异常. a.定义一个异常类继承RuntimeException. b.重写构造器。 c.在出现异常的地方用throw new 自定义对象抛出! 提醒不强烈,编译阶段不报错!!运行时才可能出现!! */ public class ExceptionDemo { public static void main(String[] args) { // try { // checkAge(-34); // } catch (ItheimaAgeIlleagalException e) { // e.printStackTrace(); // } 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("年龄合法:推荐商品给其购买~~"); } } }
ItheimaAgeIlleagalException
package com.itheima.d9_exception_custom; /** 自定义的编译时异常 1、继承Exception 2、重写构造器 */ public class ItheimaAgeIlleagalException extends Exception{ public ItheimaAgeIlleagalException() { } public ItheimaAgeIlleagalException(String message) { super(message); } }
ItheimaAgeIlleagalRuntimeException
package com.itheima.d9_exception_custom; /** 自定义的编译时异常 1、继承RuntimeException 2、重写构造器 */ public class ItheimaAgeIlleagalRuntimeException extends RuntimeException{ public ItheimaAgeIlleagalRuntimeException() { } public ItheimaAgeIlleagalRuntimeException(String message) { super(message); } }