| 方法名称 | 说明 |
|---|---|
| static List of(E…elements) | 创建一个具有指定元素的List集合对象 |
| static Set of(E…elements) | 创建一个具有指定元素的Set集合对象 |
| static | 创建一个具有指定元素的Map集合对象 |
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);//报错
System.out.println(lists);
System.out.println(score);
// 2、不可变的Set集合
//Set names = Set.of("迪丽热巴", "马尔扎哈", "卡尔眨巴", "卡尔眨巴");//不会自动扔掉一个重复的卡尔眨巴,而是直接报IllegalArgumentException异常
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);
}
}
在JDK8中,得益于Lambda所带来的函数式编程,引入了一个全新的Stream流概念,用于简化集合和数组操作的API
案例需求:
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);
//方法二:使用Stream实现
names.stream().filter(s -> s.startsWith("张") && s.length() == 3).forEach(s -> System.out.println(s));
//stream流是支持链式编程的
names.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));
}
}
Stream流式思想的核心:
Stream流的三类方法:
集合获取Stream流的方式
| 名称 | 说明 |
|---|---|
| default Stream stream() | 获取当前集合对象对的Stream流 |
数组获取Stream流的方式
| 名称 | 说明 |
|---|---|
| public static Stream stream(T[] array) | 获取当前数组的Stream流 |
| public static Stream of(T…values) | 获取当前数组/可变数据的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<>();
//这种是不对的,Map集合没有stream方法
//maps.stream()
// 键流
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.中间操作方法
| 名称 | 说明 |
|---|---|
| Stream filter(Predicate super T> predicate) | 用于对流中的数据进行过滤 |
| Stream limit(long maxSize) | 获取前几个元素 |
| Stream skip(long n) | 跳过前几个元素 |
| Stream distinct() | 去除流中重复的元素,依赖hashCode和equals方法 |
| static Stream concat(Stream extends T> a, Stream extends T> b) | 合并a和b两个流为一个流 |
| long count() | 流中还有几个元素 |
| Stream map(Function super T, ? extends R> mapper); | 加工数据 |
2.终结方法
| 名称 | 说明 |
|---|---|
| void forEach(Consumer super T> action); | 对此流的每个元素执行遍历操作 |
| long count() | 返回此流中的元素数 |
public class StreamDemo03 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("123");
list.add("1456");
list.add("26");
list.add("666");
list.add("14666");
//1.filter
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("1");
}
}).forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
//Lambda表达式简化格式
list.stream().filter(s -> s.startsWith("1")).forEach(s -> System.out.println(s));
//2.count(终止方法)
long size = list.stream().filter(s -> s.startsWith("1")).count();
System.out.println(size);
//3.limit
list.stream().filter(s -> s.startsWith("1")).limit(1).forEach(s -> System.out.println(s));
//4.skip
list.stream().filter(s -> s.startsWith("1")).skip(2).forEach(s -> System.out.println(s));
//5.map方法用来加工数据
list.stream().map(new Function<String, Integer>() {//String是原材料类型,Integer是加工后类型
@Override
public Integer apply(String s) {
return Integer.parseInt("9" + s);
}
}).forEach(s -> System.out.println(s));
//Lambda表达式简化格式
list.stream().map(s -> Integer.parseInt("9" + s)).forEach(a -> System.out.println(a));
// 需求:把所有的String都加工成一个学生对象。
list.stream().map(s -> new Student(s)).forEach(s -> System.out.println(s));
list.stream().map(Student::new).forEach(System.out::println); // 构造器引用,方法引用
//6.concat用来合并流(期间用distinct去除重复元素)
//static Stream concat(Stream extends T> a, Stream extends T> b)
Stream<String> s1 = list.stream().filter(s -> s.startsWith("1"));
Stream<String> s2 = Stream.of("2", "5", "5");
Stream<String> s3 = Stream.concat(s1, s2);
s3.distinct().forEach(s -> System.out.println(s));
//如果两个流类型不同,必须用Object类型的流来接
Stream<String> s4 = list.stream().filter(s -> s.startsWith("1"));
Stream<Integer> s5 = Stream.of(12, 11, 11);
Stream<Object> s6 = Stream.concat(s4, s5);
s6.distinct().forEach(s -> System.out.println(s));
}
}
class Student {
private String a;
public Student(String a) {
this.a = a;
}
@Override
public String toString() {
return "Student{" +
"a=" + a +
'}';
}
}
注意事项:
收集Stream流就是把Stream流操作后的结果数据转回到集合或者数组中
Stream流和StringBuilder的作用类似,只是方便我们操作的手段,我们最终还是要将Stream流转换为集合/数组
Stream流的收集方法:
| 名称 | 说明 |
|---|---|
| R collect(Collector collector) | 开始收集Stream流,指定收集器 |
Collections工具类提供了具体的收集方式
| 名称 | 说明 |
|---|---|
| public static Collector toList() | 把元素收集到List集合中 |
| public static Collector toSet() | 把元素收集到Set集合中 |
| public static Collector toMap(Function keyMapper, Function valueMapper) | 把元素收集到Map集合中 |
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("张"));//不知道为啥变量写为s就不对了,我寻思着filter的s应该是局部变量啊,为什么会变量名冲突呢
List<String> zhangList = s1.collect(Collectors.toList());
zhangList.add("java1");
System.out.println(zhangList);
//Set zhangSet = s1.collect(Collectors.toSet());//这行代码会报IllegalStateException异常,因为流只能使用一次
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[] arrs1 = s3.toArray();//toArray方法返回的是Object类型的数组,因为流中可能会有不同类型的数据
System.out.println("Arrays数组内容:" + Arrays.toString(arrs1));
/**
* 如果我已经确定我这个流里数据是同种类型(如String类型),我就想要它给我返回字符串数组怎么办:
* 1.先调用toArray方法遍历流,会清楚知道流中所有数据的类型和流中元素个数
* 2.如果确定了全部是String类型,就会调用apply(value)方法new一个长度为value的字符串数组并作为参数传给toArray方法
* 3.遍历流将元素全加到字符串数组中并返回给变量arrs
*/
Stream<String> s4 = list.stream().filter(s -> s.startsWith("张"));
String[] arrs2 = s4.toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
//简化写法
// String[] arrs2 = s4.toArray(String[]::new);
System.out.println("Arrays数组内容:" + Arrays.toString(arrs2));
}
}
说一下第12行List zhangList = s1.collect(Collectors.toList())是怎么执行的(粗略说一下,具体怎么执行还要深究源码):
直接继承自RuntimeException或者其子类,编译阶段不会报错,运行时可能出现的错误,一般是程序员业务没有考虑好或者是编程逻辑不严谨引起的程序错误
运行时异常示例:
数组索引越界异常:ArrayIndexOutOfBoundsException
空指针异常:NullPointerException,直接输出没有问题,但是调用空指针的变量的功能就会报错
数学操作异常:ArithmeticException
类型转换异常:ClassCastException
Object o = 23;
String s = (String) o;
数字转换异常:NumberFormatException
不是RuntimeException或者其子类的异常,编译阶段就报错,必须处理,否则代码不通过
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);
}
}
编译时异常的作用:
默认的异常处理机制并不好,一旦真的出现异常,程序立即死亡!
异常处理方式一:
throws:用在方法上,可以将方法内部出现的异常抛出去给本方法的调用者处理
这种方式并不好,发生异常的方法自己不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡
抛出异常格式
方法 throws 异常1, 异常2, 异常3…{
}
这是不规范的做法,因为如果一个方法要抛出10个异常,那总不能throws后面写10个异常类型吧,这里有一种规范做法:
方法 throws Exception{
}
异常处理方式二:try…catch
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) {
// 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("您的文件根本就没有啊,不要骗我哦!!");
// }
// }
// 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);
//
// InputStream is = new FileInputStream("E:/meinv.jpg");
// } catch (FileNotFoundException|ParseException e) {
// e.printStackTrace(); // 打印异常栈信息
// }
// }
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(); // 打印异常栈信息
}
}
}
下面分析一下最终的代码是怎么演变来的:
8-23演变为25-37:
25-37演变为51-59:
规范格式是:
try{
//可能出现异常的代码
}catch(Exception e){//Exception可以捕获一切异常类型
e.printStackTrace();//直接打印异常栈信息
}
所以就演变为了51-59的最终格式
异常处理方式三:前两者结合
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");
}
}
运行上述代码会发现,打印的栈信息是在最后而不是在"程序开始。。。。"和"功能操作失败~~~"之间,老师说这是人家底层用了线程机制
运行时异常可以不处理,编译阶段又不报错。按照理论规则:建议还是处理,只需要在**最外层(main方法中如果还不处理异常,就会抛给虚拟机,所以最外层也就是在main方法中)**捕获处理即可
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);
}
}
为什么chu不用写throws RuntimeException呢:
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("输的什么破东西,能不能好好输?");
}
}
}
}
第7行String priceStr = sc.nextLine();中的nextLine()不能用nextDouble()
为什么要自定义异常:
自定义异常的好处:
public class ExceptionDemo {
public static void main(String[] args) {
try {
checkAge(-34);
} catch (AgeIlleagalException e) {
e.printStackTrace();
}
public static void checkAge(int age) throws AgeIlleagalException {
if(age < 0 || age > 200){
// 抛出去一个异常对象给调用者
// throw :在方法内部直接创建一个异常对象,并从此点抛出
// throws : 用在方法申明上的,抛出方法内部的异常
throw new AgeIlleagalException(age + " is illeagal!");
}else {
System.out.println("年龄合法:推荐商品给其购买~~");
}
}
}
public class AgeIlleagalException extends Exception{
public AgeIlleagalException() {
}
public AgeIlleagalException(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 new AgeIlleagalRuntimeException(age + " is illeagal!");
}else {
System.out.println("年龄合法:推荐商品给其购买~~");
}
}
}
注意: