不可变集合
不可变集合,就是不可修改的集合
集合的数据项在创建的时候提供,兵器整个生命周期中都不可改变,否则报错
为什么要创建不可变集合?
如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践
或者当集合对象被不可新的库调用时,不可变形式是安全的
package com.itheima.d6_map_test; import java.util.*; //使用Stream流 public class StreamTest { public static void main(String[] args) { //不可变集合list集合 List<Double> lists=List.of(569.6,89.3,45.2,67.2); //lists.add(678.3); //lists.set(2,56.9); System.out.println(lists); double i=lists.get(1); System.out.println(i); //不可变的set集合 Set<String> names= Set.of("迪丽热巴","马尔扎哈"); System.out.println(names); Map<String,Integer> maps=Map.of("华为",1,"Java",2); //maps.put("是吗",3); System.out.println(maps); } }
不可变集合的特点?
定义完成后不可以修改,或者添加,删除
如何创建不可变集合?
List、Set、Map接口中,都存在of方法可以创建不可变集合
Stream流:
在Java8中,得益于Lambda所带来的函数时编程,引入了一个全新的Stream流概念
目的:用于简化集合和数组操作的API
Stream流的思想:
1.先得到集合或者数组的Stream流
2.把元素放上去
3.然后就用这个Stream流去简化的API来方便的操作元素
package com.itheima.d7_stream; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Stream; //初步体验Stream流的方便与快捷 public class StreamTest { public static void main(String[] args) { List<String> names=new ArrayList<>(); Collections.addAll(names,"张三丰","张无忌","周芷若","赵敏"); // System.out.println(names); /*List<String> zhangList = new ArrayList<>(); for (String name:names) { if(name.startsWith("张")){ zhangList.add(name); } } System.out.println(zhangList); //找名称长度是三的数据 List<String> zhangTree = new ArrayList<>(); for(String name:zhangList){ if(name.length()==3){ zhangTree.add(name); } } System.out.println(zhangTree); //Stream流*/ names.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3). forEach(s-> System.out.println(s)); } }
Stream流的作用是什么?结合了什么技术?
简化集合,数组操作的API,结合了Lambda表达式
说说Stream流的思想和使用步骤
先得到集合或者数组的Stream流
把元素放上去
然后就用这个Stream流简化的API来方便的操作元素
Stream流的三种用法:
获取Stream流
创建一条流水线,并把数据放到流水线上准备进行操作
中间方法
流水线上的操作,一次操作完毕后,还可以继续进行其他操作
终结方法:
一个Stream流只能由一个终结方法,是流水线上的最后一个操作
{ public static void main(String[] args) { /*----------Collection集合获取数据----------*/ Collection<String> list = new ArrayList<>(); Stream<String> s=list.stream(); /*------------Map集合获取流-------------*/ Map<String,Integer> map1=new HashMap<>(); //键值 Stream<String> keyStream=map1.keySet().stream(); //值流 Stream<Integer> valuesStream=map1.values().stream(); //键值对象 Stream<Map.Entry<String,Integer>> keyAndValueStream=map1.entrySet().stream(); /*-----------数值获取数据----------*/ String[] names={"赵敏","小姐","周芷若"}; Stream<String> nameStream=Arrays.stream(names); Stream<String> name=Stream.of(names); } }
集合获取Stream流的方式?
集合获取Stream的方式是通过调用stream()方法实现的
数组获取Stream流的方式?
package com.itheima.d7_stream; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class StreamTest2 { /*Stream流的常用API * forEach:逐一处理 * count:统计个数 long count() *limit:取前几个元素 *skip跳过前几个 * map:加工方法 * concat:合并流 * */ public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("张无忌"); list.add("周芷若"); list.add("赵敏"); list.add("张强"); list.add("张三丰"); 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(System.out::println); list.stream().filter(s->s.startsWith("张")).skip(2).forEach(System.out::println); //map加工方法 //给集合元素的前面加上一个黑马字样 list.stream().map(s->"黑马的"+s).forEach(System.out::println); //需求把所有的名称加工成一个学生对象 list.stream().map(s-> new Student(s)).forEach(s-> System.out.println(s)); //合并流 Stream<String> s1=list.stream().filter(s->s.startsWith("张")); Stream<String> s2=Stream.of("Java1","Java2"); Stream<String> s3=Stream.concat(s1,s2); s3.forEach(s-> System.out.println(s)); } }
注意:中间方法也称为非终结方法,调用完成后返回新的Stream流可以继续使用,支持链式编程
在Stream流中无法修改集合,数组中的数据
注意:终结操作方法,调用完后流就无法继续使用了,原因是不会返回Stream了
总结:终结和非终结方法的含义是什么?
终结方法后流不可以继续使用,非终结方法会返回新的流,支持链式编程
Stream流的收集操作:
收集Stream流的含义:就是把Stream流操作后的结果数据转回到集合或者数组中去
Stream流:方便操作集合/数组的手段
集合/数组:才是开发中的目的
package com.itheima.d7_stream; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; public class StreamTest3 { //收集Stream流的数据到集合或者数组中去 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()); System.out.println(zhangList); //流只能使用一次 Stream<String> s2=list.stream().filter(s->s.startsWith("张")); Set<String> zhang=s2.collect(Collectors.toSet()); System.out.println(zhang); } }
收集Stream流的作用?
Stream流是操作集合/数组的手段
操作的结果数据最终要恢复到集合或者数组中去
异常处理:
异常概述:异常是程序在"编译"或者"运行的过程中可能出现的问题,注意:语法错误不算在异常体系中
比如:数组索引越界、空指针异常、日期格式化异常,等
为什么要学习异常?
异常一旦出现了,如果没有提前处理,程序就会推出JVM虚拟机而终止
1.异常是什么?
异常是代码在编译或者执行的过程中可能出现的错误
2.异常分为几类?
编译时异常,运行时异常
编译时异常:没有继承RuntimeExcpetion的异常, 编译阶段就会报错
运行时异常:继承自RuntimeExcpetion的异常或其子类,编译阶段不报错,运行可能报错
3.学习异常的目的?
避免异常的出现,同时可能出现的异常,让代码更稳健
编译时异常的特点?
编译时异常:继承自Exception的异常或者其子类
编译阶段报错,必须处理,否则代码不通过
异常的默认处理流程?
默认会出现异常的代码那里自动的创建一个异常对象:ArithmeticException
异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机
虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据
直接从当前的异常点干掉当前程序
后续代码没有机会执行了,因为程序已经死亡了
默认异常处理机制:
默认的异常处理机制不好,一旦真的出现异常,程序立即死亡
编译时异常是编译阶段就会出错的,所以必须处理,否则代价根本无法通过
编译时异常的处理形式有三种:
出现异常直接跑出去给调用者,调用者也继续抛出去
出现异常自己捕获处理,不麻烦别人
前两者结合,出现异常直接抛出去给调用者,调用者捕获处理
异常处理方式:----throws
throws:用在方法上,可以将方法内部出现的异常抛出去给本方法的调用者处理
这种方法并不好,发生异常的方法自己不处理异常,如果异常最终跑出去给虚拟机将引起程序死亡
抛出异常格式:
方法 throws 异常1,异常2,异常3...{ }
规范做法:
方法 throws Exception{}
异常处理方式2---try..catch...
监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理
这种方式还可以,发生异常的方法自己独立完成异常的处理,程序可以继续往下执行
格式: 建议格式:
try{
}catch(异常类型1 变量){
}catch(异常类型2 变量){
}
异常处理方式3----前两者结合
方法直接将异常通过throwa跑出去给调用者
调用者收到异常后直接捕获处理
运行时异常的处理形式:
运行时异常编译阶段不会出现,是运行时才可能出错的,所以编译阶段不处理也可以
按照规范建议还是处理:建议在最外层调用处集中捕获处理即可
自定义异常的必要?
Java无法为这个世界上全部的问题提供异常类
如果企业向通过异常的方式来管理自己的某个业务问题,就需要自定义异常类了
自定义异常的好处:
可以使用异常的机制管理业务问题,提醒程序员注意
同时一旦出现bug,可以用异常的形式清晰的指出出错的地方
自定义异常的分类:
1.自定义编译时异常
2.定义一个异常继承Exception
3.重写构造器
在出现异常的地方用throw new自定义对象抛出
作用:编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理
自定义运行时异常
定义一个异常类继承RuntimeException
重写构造器
在出现异常的地方用throw new 自定义对象抛出
作用:提醒不强烈,编译阶段不报错,运行时才可能出现