不可变集合
不可变集合,就是不可修改的集合
集合的数据项在创建的时候提供,兵器整个生命周期中都不可改变,否则报错
为什么要创建不可变集合?
如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践
或者当集合对象被不可新的库调用时,不可变形式是安全的
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 自定义对象抛出
作用:提醒不强烈,编译阶段不报错,运行时才可能出现










