1.Stream流:
Stream流的概述:
Stream流指的是流式编程,用于简化集合和数组的操作。结合了lambda表达式。
Stream流式思想的核心:
1.先得到集合或者数组的Steam流。(传送带)
2.然后用Stream流提供的方法对流中的数据进行操作。(加工的环节)
public class Demo1 { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("张无忌"); list.add("周芷若"); list.add("赵敏"); list.add("张强"); list.add("张三丰"); //Stream流式编程,可以简化集合的操作,得到开头为张,字符串长度为3的新数组并遍历。 list.stream().filter(s->s.startsWith("张")).filter(s->s.length()==3).forEach(s-> System.out.println(s)); } }
Stream流的获取:
只有单列集合才有获取Stream流的方法,双列集合必须转换为单列集合才能获取Stream流。
public class Demo2 { public static void main(String[] args) { //1.通过List、Set集合获取流 //ArrayList<String> list = new ArrayList<>(); HashSet<String> list = new HashSet<>(); Collections.addAll(list, "张三丰","张无忌","张良","谢广坤","小龙女","尹志平"); /** * default Stream<E> steam();获取当前集合对象的Stream流。 */ //调用stream()方法获取流, 并遍历输出元素 list.stream().forEach(s -> System.out.println(s)); System.out.println("-----------------"); //2.通过Map集合获取流(Map集合不能直接获取流) HashMap<String,String> map = new HashMap<>(); map.put("王宝强", "马蓉"); map.put("贾乃亮", "李小璐"); //2.1获取map的键集,再获取流 map.keySet().stream().forEach(s -> System.out.println(s)); //2.2获取map的值集,再获取流 map.values().stream().forEach(s -> System.out.println(s)); //2.3获取map键值对的集合,再获取流 map.entrySet().stream().forEach(s-> System.out.println(s.getKey()+"..."+s.getValue())); System.out.println("--------------------------------------------------"); //3.通过数组、元素获取流,需要传入的是引用数据类型,如果传入基本数据类型,返回的只是地址值。 /** * public static<T> Stream<T> of(T... values):获取当前数组/可变数据的Stream流。 */ Integer[] arr = {10,20,30,40,50}; Stream.of(arr).forEach(s-> System.out.println(s)); int[] arr1= {10,20,34,40}; Stream.of(arr1).forEach(s-> System.out.println(s)); int[] arr2= {10,20,34,40}; Arrays.stream(arr2).forEach(s-> System.out.println(s)); } }
Stream流的常用API:
1.Stream流的常用API(中间操作方法)
注意:
1.中间方法也称为非终结方法,调用完成后返回新的Stream流可以继续使用,支持链式编程。
2.在Stream流中无法直接修改集合,数组的数据。
public class Demo3 { public static void main(String[] args) { List<String> list1 = new ArrayList<>(); List<String> list2 = new ArrayList<>(); Collections.addAll(list1, "杨过","小龙女","周伯通","欧阳锋","尹志平","金轮法王"); Collections.addAll(list2, "孙二娘","武松","武大郎","西门庆","潘金莲","潘金莲","张青"); //1.concat(Stream a,Stream b)把a,b两个流合并为一个流 Stream<String> stream = Stream.concat(list1.stream(), list2.stream()); //2.filter(Predicate<? super T> predicate)用于对流中的数据进行过滤 stream.filter(s->s.length()>=3).forEach(s-> System.out.println(s)); System.out.println("------------------------------"); //3.limit(long maxSize)获取前几个元素。 Stream.concat(list1.stream(),list2.stream()).limit(10).forEach(s-> System.out.println(s)); System.out.println("------------------------------"); //4.skip(long n)跳过前面几个元素。 Stream.concat(list1.stream(),list2.stream()).skip(3).forEach(s-> System.out.println(s)); System.out.println("------------------------------"); //5.distinct()去除流中重复的元素,依赖(hashCode和equals方法) list2.stream().distinct().forEach(s-> System.out.println(s)); System.out.println("------------------------------"); //由于filter、limit、skip等这些方法都是中间操作方法,返回值也是一个流,所以支持链式编程(流式编程) //"欧阳锋","尹志平","金轮法王","孙二娘","武大郎","西门庆","潘金莲" Stream.concat(list1.stream(),list2.stream()) .filter(s->s.length()>=3) .limit(10) .skip(2) .distinct() .forEach(s-> System.out.println(s)); } }
2.Stream流的常用终结操作方法
注意:
终结操作方法,调用完成后流就无法继续使用了,原因是不会返回Stream了。
public class Demo4 { public static void main(String[] args) { List<String> list1 = new ArrayList<>(); Collections.addAll(list1, "杨过","小龙女","周伯通","欧阳锋","尹志平","金轮法王"); //1.forEach(Consumer action)对此流的每个元素执行遍历操作。 list1.stream().filter(s -> s.length()==3).forEach(s-> System.out.println(s)); System.out.println("-----------------------------------"); //2.long count()返回此流中的元素数。 long count = list1.stream().filter(s -> s.length() == 3).count(); System.out.println(count); } }
Stream流的综合应用:
public class Demo5 {
public static void main(String[] args) {
ArrayList<Empolyee> list1 = new ArrayList<>();
list1.add(new Empolyee("孙悟空","石",20000,5000,"大闹天宫"));
list1.add(new Empolyee("沙和尚","男",15000,3000,"打碎琉璃盏"));
list1.add(new Empolyee("猪八戒","公",13000,2000,"调戏嫦娥"));
list1.add(new Empolyee("白龙马","公",14000,6000,"杀了鲤鱼精"));
ArrayList<Empolyee> list2 = new ArrayList<>();
list2.add(new Empolyee("西门庆","男",30000,-5000,"被武松打死"));
list2.add(new Empolyee("潘金莲","女",2000,300,"被武松打死"));
list2.add(new Empolyee("武大郎","男",5000,3000,"吃药"));
list2.add(new Empolyee("武松","男",25000,10000,"发配沧州"));
//分别获取两个部门的Stream流
//Stream<Empolyee> stream1 = list1.stream();
//Stream<Empolyee> stream2 = list2.stream();
//2.分别将流中的元素从Employee对象转换为员工的实际收入
Stream<Double> moneyStream1 = list1.stream().map(s -> s.getMoney());
moneyStream1.forEach(s-> System.out.println(s));
list2.stream().map(s -> s.getMoney()).forEach(s -> System.out.println(s));
//3.分别求两个部门的平均月收入
//mapToDouble(lambda表达式): 把流中的元素转换为double类型,返回值是DoubleStream
//average():求DoubleStream中元素的平均值,返回值OptionalDouble
//getAsDouble(): 获取到OptionalDouble里面封装的double值
double avg1 = list1.stream().mapToDouble(s -> s.getMoney()).average().getAsDouble();
double avg2 = list2.stream().mapToDouble(s -> s.getMoney()).average().getAsDouble();
System.out.println("开发一部的平均收入是:"+avg1);
System.out.println("开发二部的平均收入是:"+avg2);
System.out.println("--------------------");
//4.分别筛选出两个部门的最高收入的员工信息
//max(比较器):求流中元素的最大值,返回值是Optional对象(它是有一个封装有元素的包装类)
//get(): 获取Optional包装类中封装的元素对象
Empolyee max1 = list1.stream().max((o1, o2) -> Double.compare(o1.getMoney(), o2.getMoney())).get();
Empolyee max2 = list2.stream().max((o1, o2) -> Double.compare(o1.getMoney(), o2.getMoney())).get();
System.out.println("开发一部收入最高的员工信息:"+max1);
System.out.println("开发二收入最高的员工信息:"+max2);
System.out.println("--------------------");
//5.分别对两个部门的员工按照实际收入进行排序
list1.stream().sorted((o1, o2) -> Double.compare(o1.getMoney(), o2.getMoney())).forEach(s-> System.out.println(s));
list2.stream().sorted((o1, o2) -> Double.compare(o1.getMoney(), o2.getMoney())).forEach(s-> System.out.println(s));
//6.统计2个开发部门整体的平均月收入,要求去掉最高收入和最低收入。
double avg = Stream.concat(list1.stream(), list2.stream())
.sorted((o1, o2) -> Double.compare(o1.getMoney(), o2.getMoney()))
.limit(list1.size() + list2.size() - 1)
.skip(1)
.mapToDouble(s -> s.getMoney())
.average()
.getAsDouble();
System.out.println("两个部门的整体平均月收入:"+avg);
}
}
收集Stream流:
/**
* Stream流的收集方法:
* collect(Collector collector):开始搜集Stream流,指定收集器。
* public static <T> Collector toList(): 把元素收集到List集合中。
* public static <T> Collector toSet(): 把元素收集到Set集合中。
* public static Collector toMap(Function KeyMapper,Function valueMapper):把元素收集到Map集合中。
*/
public class Demo6 {
public static void main(String[] args) {
ArrayList<Empolyee> list1 = new ArrayList<>();
list1.add(new Empolyee("孙悟空","石",20000,5000,"大闹天宫"));
list1.add(new Empolyee("沙和尚","男",15000,3000,"打碎琉璃盏"));
list1.add(new Empolyee("猪八戒","公",13000,2000,"调戏嫦娥"));
list1.add(new Empolyee("白龙马","公",14000,6000,"杀了鲤鱼精"));
List<Empolyee> list = list1.stream().filter(s -> s.getSalary() >= 14000).collect(Collectors.toList());
System.out.println(list);
Set<Empolyee> set = list1.stream().filter(s -> s.getSalary() >= 14000).collect(Collectors.toSet());
System.out.println(set);
Map<String, Integer> map = list1.stream().filter(s -> s.getSalary() >= 14000).collect(Collectors.toMap(s -> s.getName(), s -> s.getSalary()));
System.out.println(map);
Object[] arr1 = list1.stream().filter(s -> s.getSalary() >= 14000).toArray();
for (Object o : arr1) {
System.out.println(o);
}
Empolyee[] arr2 = list1.stream().filter(s -> s.getSalary() >= 14000).toArray(value -> new Empolyee[value]);
for (Empolyee empolyee : arr2) {
System.out.println(empolyee);
}
}
}
2.异常:
异常是程序在编译或者执行的过程中可能出现的问题。Java语言的设计者们为了让开发者知道,异常产生的原因,把这些异常设计成了类。
目的:
- 避免异常的出现
- 提前处理可能出现的异常,让代码更稳健。
常见运行时异常:
public class Demo2 {
public static void main(String[] args) {
//1.ArrayIndexOutOfBoundsException: 数组索引越界
// int[] arr1=new int[3];
// System.out.println(arr1[arr1.length]);
//2.StringIndexOutOfBoundsException: 字符串索引越界
// String str="aaa";
// System.out.println(str.charAt(str.length()));
//3.IndexOutOfBoundsException: 集合的索引越界
// List<String> list=new ArrayList();
// System.out.println(list.get(list.size()));
//4.NullPointerException: 空指针异常
// int[] arr4=null;
// System.out.println(arr4.length);
//5.ClassCastException: 类型转换异常
// List<String> list=new ArrayList<>();
// LinkedList<String> list1=(LinkedList<String>) list;
//6.NumberFormatException: 数字格式异常
// int num=Integer.parseInt("ass");
//7.ArithmeticException: 数学操作异常
// int a=23/0;
//8.IllegalArgumentException: 非法参数异常
// Random ran=new Random();
// int num=ran.nextInt(0);
}
}
编译时异常:
不管代码是否真的有问题,在编译阶段就会报错,目的是提醒程序员不要出错。
特点:继承自Exception的异常或者其子类。
必须处理,否则代码不通过。
异常如何产生:
在写一个方法时,考虑到调用者可能传递非法数据,需要对调用者传递过来的数据进行合法性的校验,如何数据校验不合法就通过throw new 产生一个异常对象,并抛给调用者,让调用者知道为什么错了。
注意:
- 如果方法中产生的是运行时异常,不需要在方法上声明。
- 如果方法中产生的是编译时异常,需要在方法上用throws声明。
public class Demo4 { public static void main(String[] args) throws Exception { test(0); } public static void test(int num) throws Exception { if (num<1||num>100){ throw new Exception("参数有问题啊!"); } System.out.println("正常执行"); } }
遇到异常该如何处理
/** 遇到异常如何处理: 方案1: try...catch捕获异常格式 try{ 有可能产生异常的代码 }catch(Exception e){ 如果try里面产生了异常,异常对象会赋值给这里变量e 在这里可以处理异常 } 特点:处理异常之后,程序还可以继续执行 方案2: throws 在方法上声明异常,把异常交给下一个调用者,由调用者处理 public void 方法名() throws 异常类{ 有异常产生的代码 } */ public class Demo5 { public static void main(String[] args) { while (true) { try { Scanner sc = new Scanner(System.in); int num = sc.nextInt(); System.out.println("你录入的数据是:"+num); break; } catch (Exception e) { //e.printStackTrace(); //打印异常信息 System.out.println("你录入的数据格式不对,请重新录入"); } } System.out.println("over"); System.out.println("---------------"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); Date date = null; try { date = sdf.parse("2008-08-08"); } catch (ParseException e) { //e.printStackTrace(); System.out.println("你解析的日期字符串格式不对"); } System.out.println(date); } }
注意:
- 如果遇到的是运行时异常,一般不需要处理,直接改代码就行。如果改代码解决不了,也能使用try...catch处理。
- 如果遇到编译时异常,可以使用try...catch捕获异常,也可以继续使用throws声明,抛给下一个调用者处理。
自定义异常类:
- 如果Java的API中提供的异常类,不足以描述你的问题;那么你就可以自定义异常类。
- 只需要让自定义类继承Exception或者RuntimeException即可。