java笔记06
TreeMap的基本使用
TreeMapTreeMap 跟 TreeSet 底层原理一样,都是红黑树结构的。由键决定特性:不重复、无索引、可排序可排序:对键进行排序。注意:默认按照键的从小到大进行排序,也可以自己规定键的排序规则 代码书写两种排序规则实现 Comparable 接口,指定比较规则。创建集合时传递 Comparator 比较器对象,指定比较规则。
Test1
package a02_双列集合Map.a07_TreeMap的基本使用;import java.util.Comparator; import java.util.TreeMap;public class Test1 {public static void main(String[] args) {/*TreeMap 集合:基本应用需求 1:键:整数表示 id值:字符串表示商品名称要求:按照 id 的升序排列、按照 id 的降序排列*///1. 创建集合对象//Integer Double 默认情况下都是按照升序排列的//String 按照字母在 ASCII 码表中对应的数字升序进行排列//升序 // TreeMap<Integer,String> tm = new TreeMap<>();//降序TreeMap<Integer,String> tm = new TreeMap<>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {//o1: 当前要添加的元素//o2:表示已经在红黑树中存在的元素return o2 - o1;}});//2. 添加元素tm.put(5,"可怡可乐");tm.put(4,"雷碧");tm.put(3,"九个核桃");tm.put(2,"康帅傅");tm.put(1,"粤利粤");//3. 打印集合System.out.println(tm);} }
Test2
package a02_双列集合Map.a07_TreeMap的基本使用;import java.util.TreeMap;public class Test2 {public static void main(String[] args) {/*TreeMap 集合:基本应用需求 2:键:学生对象值:籍贯要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名年龄视为同一个人。*///1.创建集合TreeMap<Student,String> tm = new TreeMap<>();//2.创建三个学生对象Student s1 = new Student ("zhangsan", 23);Student s2 = new Student ("lisi", 24);Student s3 = new Student ("wangwu", 25);//3.添加元素tm.put(s1,"江苏");tm.put(s2,"天津");tm.put(s3,"北京");//4.打印集合System.out.println(tm);} }
package a02_双列集合Map.a07_TreeMap的基本使用;public class Student implements Comparable<Student>{private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic int compareTo(Student o) {//按学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名年龄视为同一个人。//this:表示当前要添加的元素//o:表示已经在红黑树中存在的元素// 返回值:// 负数:表示当前要添加的元素是小的,存左边// 正数:表示当前要添加的元素是大的,存右边//0:表示当前要添加的元素已经存在,舍弃int i = this.getAge () - o.getAge ();i = i == 0? this.getName ().compareTo (o.getName ()) : i;return i;} }
Test3
package a02_双列集合Map.a07_TreeMap的基本使用;import java.util.StringJoiner; import java.util.TreeMap;public class Test3 {public static void main(String[] args) {/* 需求:字符串 “aababcabcdabcde”请统计字符串中每一个字符出现的次数,并按照以下格式输出输出结果:a(5)b(4)c(3)d(2)e(1)新的统计思想:利用 map 集合进行统计如果题目中没有要求对结果进行排序,默认使用 HashMap如果题目中要求对结果进行排序,请使用 TreeMap键:表示要统计的内容值:表示次数*///1. 定义字符串String s = "aababcabcdabcde";//2. 创建集合TreeMap<Character,Integer> tm = new TreeMap<>();//3. 遍历字符串得到里面的每一个字符for (int i = 0; i < s.length (); i++) {char c = s.charAt (i);// 拿着 c 到集合中判断是否存在// 存在,表示当前字符又出现了一次// 不存在,表示当前字符是第一次出现if (tm.containsKey (c)){// 存在// 先把已经出现的次数拿出来int count = tm.get (c);// 当前字符又出现了一次count++;// 把自增之后的结果再添加到集合当中tm.put (c,count);} else {// 不存在tm.put (c,1);}}//4. 遍历集合,并按照指定的格式进行拼接//a(5)b(4)c(3)d(2)e(1)StringBuilder sb = new StringBuilder ();tm.forEach((key,value)->{ sb.append(key).append("(").append(value).append(")"); });StringJoiner sj = new StringJoiner("", "", "");tm.forEach((key, value)->sj.add(key + "").add("(").add(value + "").add(")"));System.out.println(sb);System.out.println(sj);} }
TreeMap总结: TreeMap 集合的特点是怎么样的? 不重复、无索引、可排序 底层基于红黑树实现排序,增删改查性能较好 TreeMap 集合排序的两种方式 实现 Comparable 接口,指定比较规则 创建集合时传递 Comparator 比较器对象,指定比较规则
可变参数
package a08_可变参数;public class Test1 {public static void main(String[] args) {//JDK5// 可变参数// 方法形参的个数是可以发生变化的,0 1 2 3 ...// 格式:属性类型... 名字// int...argsint sum = getSum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);System.out.println(sum);}// 底层:// 可变参数底层就是一个数组// 只不过不需要我们自己创建了,Java 会帮我们创建好public static int getSum(int... args) {//System.out.println (args);//[I@119d7047int sum = 0;for (int i : args) {sum = sum + i;}return sum;} }
package a08_可变参数;public class Test2 {public static void main(String[] args) {// 可变参数的小细节://1. 在方法的形参中最多只能写一个可变参数// 可变参数,理解为一个大胖子,有多少吃多少//2. 在方法的形参当中,如果出了可变参数以外,还有其他的形参,那么可变参数要写在最后getSum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);}public static int getSum(int a, int... args) {return 0;} }
集合工具类Collections
Collections java.util.Collections: 是集合工具类 作用:Collections 不是集合,而是集合的工具类。Collections 常用的 API 方法名称 说明 public static <T> boolean addAll(Collection<T> c, T... elements) 批量添加元素 public static void shuffle(List<?> list) 打乱 List 集合元素的顺序 public static <T> void sort(List<T> list) 排序 public static <T> void sort(List<T> list, Comparator<T> c) 根据指定的规则进行排序 public static <T> int binarySearch (List<T> list, T key) 以二分查找法查找元素 public static <T> void copy(List<T> dest, List<T> src) 拷贝集合中的元素 public static <T> int fill (List<T> list, T obj) 使用指定的元素填充集合 public static <T> void max/min(Collection<T> coll) 根据默认的自然排序获取最大/小值 public static <T> void swap(List<?> list, int i, int j) 交换集合中指定位置的元素
//addAll 批量添加元素 //1. 创建集合对象 ArrayList<String> list = new ArrayList<>(); //2. 批量添加元素 Collections.addAll (list, "abc","bcd","qwer","df","asdf","zxcv","1234","qwer"); //3. 打印集合 System.out.println (list);//shuffle 打乱 Collections.shuffle (list); System.out.println (list);
综合练习
1.随机点名器的两种实现方式
package a10_综合练习.a01_随机点名器的两种实现方式;import java.util.ArrayList; import java.util.Collections;public class Test {public static void main (String [] args) {/* 班级里有 N 个学生,学生属性:姓名,年龄,性别。实现随机点名器。*///1.定义集合ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll (list, "范闲","范建","范统","杜子腾","杜琦燕","宋合泛","侯笼藤","朱益群","朱穆朗玛峰","袁明媛");//3.随机点名//第一种 // Random r = new Random (); // int index = r.nextInt (list.size ()); // String name = list.get (index); // System.out.println (name);//第二种//打乱Collections.shuffle (list);String name = list.get (0);System.out.println (name);} }
2.带有概率的随机点名
package a10_综合练习.a02_带有概率的随机点名;import java.util.ArrayList; import java.util.Collections; import java.util.Random;public class Test {public static void main(String[] args) {/* 班级里有 N 个学生要求:70% 的概率随机到男生30% 的概率随机到女生"范闲","范建","范统","杜子腾","宋合泛","侯笼藤","朱益群","朱穆朗玛峰","杜琦燕","袁明媛","李猜","田蜜蜜",*///1.创建集合ArrayList<Integer> list = new ArrayList<>();//2.添加数据Collections.addAll(list, 1, 1, 1, 1, 1, 1, 1);Collections.addAll(list, 0, 0, 0);//3.打乱集合中的数据Collections.shuffle(list);//4.从 list 集合中随机抽取 0 或者 1Random r = new Random();int index = r.nextInt(list.size());int number = list.get(index);System.out.println(number);//5. 创建两个集合分别存储男生和女生的名字ArrayList<String> boyList = new ArrayList<>();ArrayList<String> girlList = new ArrayList<>();Collections.addAll(boyList, "范闲", "范建", "范统", "杜子腾", "宋合泛", "侯笼藤", "朱益群", "朱穆朗玛峰");Collections.addAll(girlList, "杜琦燕", "袁明媛", "李猜", "田蜜蜜");//6. 判断此时是从 boyList 里面抽取还是从 girlList 里面抽取if (number == 1) {//boyListint boyIndex = r.nextInt(boyList.size());String name = boyList.get(boyIndex);System.out.println(name);} else {//girlListint girlIndex = r.nextInt(girlList.size());String name = girlList.get(girlIndex);System.out.println(name);}} }
3.不重复的随机点名
package a10_综合练习.a03_不重复的随机点名;import java.util.ArrayList; import java.util.Collections; import java.util.Random;public class Test {public static void main(String[] args) {/* 班级里有 5 个学生要求:被点到的学生不会再被点到。但是如果班级中所有的学生都点完了,需要重新开启第二轮点名。*///1.定义集合ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "范闲", "范建", "范统", "杜子腾", "杜琦燕", "宋合泛", "侯笼藤", "朱益群", "朱穆朗玛峰", "袁明媛");//3.随机点名// 创建一个临时的集合,用来存已经被点到学生的名字ArrayList<String> list2 = new ArrayList<>();// 外循环:表示轮数for (int i = 1; i <= 10; i++) {System.out.println ("======== 第" + i + "轮点名开始了 =================");//3. 获取集合的长度int count = list1.size ();//4. 随机点名Random r = new Random ();// 内循环:每一轮中随机循环抽取的过程for (int j = 0; j < count; j++) {int index = r.nextInt (list1.size ());String name = list1.remove (index);list2.add (name);System.out.println (name);}// 此时表示一轮点名结束//list1 空了 list2 10 个学生的名字list1.addAll (list2);list2.clear ();}} }
4.集合嵌套
package a10_综合练习.a04_集合嵌套;import java.util.*;public class Test {public static void main(String[] args) {/* 需求定义一个 Map 集合,键用表示省份名称 province,值表示市 city,但是市会有多个。添加完毕后,遍历结果格式如下:江苏省 = 南京市,扬州市,苏州市,无锡市,常州市湖北省 = 武汉市,孝感市,十堰市,宜昌市,鄂州市河北省 = 石家庄市,唐山市,邢台市,保定市,张家口市 *///1.创建 Map 集合HashMap<String, ArrayList<String>> hm = new HashMap<>();//2.创建单列集合存储市ArrayList<String> city1 = new ArrayList<>();city1.add ("南京市");city1.add ("扬州市");city1.add ("苏州市");city1.add ("无锡市");city1.add ("常州市");ArrayList<String> city2 = new ArrayList<>();city2.add ("武汉市");city2.add ("孝感市");city2.add ("十堰市");city2.add ("宜昌市");city2.add ("鄂州市");ArrayList<String> city3 = new ArrayList<>();city3.add ("石家庄市");city3.add ("唐山市");city3.add ("邢台市");city3.add ("保定市");city3.add ("张家口市");//3.把省份和多个市添加到 map 集合hm.put ("江苏省",city1);hm.put ("湖北省",city2);hm.put ("河北省",city3);Set<Map.Entry<String, ArrayList<String>>> entries = hm.entrySet();for (Map.Entry<String, ArrayList<String>> entry : entries) {//entry 依次表示每一个键值对对象String key = entry.getKey ();ArrayList<String> value = entry.getValue();StringJoiner sj = new StringJoiner(", ", "", "");for (String city : value) {sj.add(city);}System.out.println(key + " = " + sj);}} }
阶段项目斗地主
1.准洗发
package 斗地主;import java.util.ArrayList; import java.util.Collections;public class PokerGame {// 牌盒//♦3 ♠3static ArrayList<String> list = new ArrayList<>();// 静态代码块// 特点:随着类的加载而在加载的,而且只执行一次。static {// 准备牌// "♦", "♠", "♥", "♣"// "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"String[] color = {"♦", "♠", "♥", "♣"};String[] number = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};for (String c : color) {//c 依次表示每一种花色for (String n : number) {//n 依次表示每一个数字list.add(c + n);}}list.add("小王");list.add("大王");}public PokerGame() {// 洗牌Collections.shuffle(list);// 发牌ArrayList<String> lord = new ArrayList<>();ArrayList<String> player1 = new ArrayList<>();ArrayList<String> player2 = new ArrayList<>();ArrayList<String> player3 = new ArrayList<>();// 遍历牌盒得到每一张牌for (int i = 0; i < list.size(); i++) {//i:索引String poker = list.get(i);if (i <= 2) {lord.add(poker);continue;}// 给三个玩家轮流发牌if (i % 3 == 0) {player1.add(poker);} else if (i % 3 == 1) {player2.add(poker);} else {player3.add(poker);}}// 看牌lookPoker ("底牌",lord);lookPoker ("钢脑壳",player1);lookPoker ("大帅比",player2);lookPoker ("蛋筒",player3);}/*参数一:玩家的名字参数二:每位玩家的牌*/public void lookPoker (String name, ArrayList<String> list){System.out.print(name + ":");for (String poker : list) {System.out.print(poker + " ");}System.out.println();} }
2.第一种排序方式
package a02_第一种排序方式;import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.TreeSet;public class PokerGame {// 牌盒 Map// 此时我们只要把牌跟序号产生对应关系就可以了,不需要按照序号进行排序,所以只要 HashMap 就可以了static HashMap<Integer, String> hm = new HashMap<>();static ArrayList<Integer> list = new ArrayList<>();static {String[] color = {"♦", "♠", "♥", "♣"};String[] number = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};// 序号int serialNumber = 1;// 细节for (String n : number) {// 依次表示每一个数字for (String c : color) {// 依次表示每一个花色hm.put(serialNumber, c + n);list.add(serialNumber);serialNumber++;}}hm.put(serialNumber, "小王");list.add(serialNumber);serialNumber++;hm.put(serialNumber, "大王");list.add(serialNumber);}public PokerGame() {// 洗牌Collections.shuffle(list);// 发牌TreeSet<Integer> lord = new TreeSet<>();TreeSet<Integer> player1 = new TreeSet<>();TreeSet<Integer> player2 = new TreeSet<>();TreeSet<Integer> player3 = new TreeSet<>();for (int i = 0; i < list.size(); i++) {//i : 依次表示集合中的每一个索引//list.get (i) 元素:牌的序号int serialNumber = list.get(i);if (i <= 2) {lord.add(serialNumber);continue;}if (i % 3 == 0) {player1.add(serialNumber);} else if (i % 3 == 1) {player2.add(serialNumber);} else {player3.add(serialNumber);}}// 看牌lookPoker("底牌", lord);lookPoker("钢脑壳", player1);lookPoker("大帅比", player2);lookPoker("蛋筒", player3);}public void lookPoker(String name, TreeSet<Integer> ts) {System.out.print(name + ":");// 遍历 TreeSet 集合得到每一个序号,再拿着序号到 Map 集合中去找真正的牌for (int serialNumber : ts) {String poker = hm.get(serialNumber);System.out.print(poker + " ");}System.out.println();} }
3.第二种排序方式
package a03_第二种排序方式;import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap;public class PokerGame {// 牌盒//♦3 ♠3static ArrayList<String> list = new ArrayList<>();// 创建一个集合,用来添加牌的价值static HashMap<String, Integer> hm = new HashMap<>();// 静态代码块// 特点:随着类的加载而在加载的,而且只执行一次。static {// 准备牌// "♦", "♠", "♥", "♣"// "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"String[] color = {"♦", "♠", "♥", "♣"};String[] number = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};for (String c : color) {//c 依次表示每一种花色for (String n : number) {//n 依次表示每一个数字list.add(c + n);}}list.add(" 小王");list.add(" 大王");// 指定牌的价值// 牌上的数字到 Map 集合中判断是否存在// 存在,获取值// 不存在,本身的数字就是价值hm.put("J", 11);hm.put("Q", 12);hm.put("K", 13);hm.put("A", 14);hm.put("2", 15);hm.put("小王", 50);hm.put("大王", 100);}public PokerGame() {// 洗牌Collections.shuffle(list);// 发牌ArrayList<String> lord = new ArrayList<>();ArrayList<String> player1 = new ArrayList<>();ArrayList<String> player2 = new ArrayList<>();ArrayList<String> player3 = new ArrayList<>();// 遍历牌盒得到每一张牌for (int i = 0; i < list.size(); i++) {//i:索引String poker = list.get(i);if (i <= 2) {lord.add(poker);continue;}// 给三个玩家轮流发牌if (i % 3 == 0) {player1.add(poker);} else if (i % 3 == 1) {player2.add(poker);} else {player3.add(poker);}}//排序order(lord);order(player1);order(player2);order(player3);}//利用牌的价值进行排序//参数:集合//♠5 ♣3 ♥6 ♦7 ♣9public void order(ArrayList<String> list) {Collections.sort(list, new Comparator<String>() {//Array.sort(插入排序 + 二分查找)@Overridepublic int compare(String o1, String o2) {//o1:表示当前要插入到有序序列中的牌//o2:表示已经在有序序列中存在的牌//负数:o1小 插入到前面//正数:o1大 插入到后面//0:o1的数字跟o2的数字是一样的,需要按照花色再次排序//1.计算o1的花色和价值String color1 = o1.substring(0, 1);int value1 = getValue(o1);//2.计算o2的花色和价值String color2 = o2.substring(0, 1);int value2 = getValue(o2);//3.比较o1和o2的价值int i = value1 - value2;return i == 0? color1.compareTo(color2) : i;}});}//计算牌的价值//参数:牌//返回值:价值public int getValue(String poker) {//获取牌上的数字String number = poker.substring(1);//拿着数字到map集合中判断是否存在if (hm.containsKey(number)) {//存在,获取价值return hm.get(number);} else {//不存在,类型转换return Integer.parseInt(number);}} }
不可变集合
创建不可变集合 的应用场景 如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践。 或者当集合对象被不可信的库调用时,不可变形式是安全的。 简单理解:不想让别人修改集合中的内容创建不可变集合的书写格式 在 List、Set、Map 接口中,都存在静态的 of 方法,可以获取一个不可变的集合。 方法名称 说明 static <E> List<E> of(E...elements) 创建一个具有指定元素的 List 集合对象 static <E> Set<E> of(E...elements) 创建一个具有指定元素的 Set 集合对象 static <K, V> Map<K, V> of(E...elements) 创建一个具有指定元素的 Map 集合对象 注意:这个集合不能添加,不能删除,不能修改。
/*创建不可变的List集合"张三", "李四", "王五", "赵六" *///一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作 List<String> list = List.of("张三", "李四", "王五", "赵六");System.out.println(list.get(0)); System.out.println(list.get(1)); System.out.println(list.get(2)); System.out.println(list.get(3));System.out.println("---------------------");for (String s : list) {System.out.println(s); }System.out.println("---------------------");Iterator<String> it = list.iterator(); while(it.hasNext()){String s = it.next();System.out.println(s); }System.out.println("---------------------");for (int i = 0; i < list.size(); i++) {String s = list.get(i);System.out.println(s); }System.out.println("---------------------");//list.remove("李四"); // 报错 //list.add("aaa"); // 报错 //list.set(0,"aaa"); // 报错
package a11_不可变集合;import java.util.Iterator; import java.util.Set;public class a02_创建不可变的Set集合 {public static void main(String[] args) {/*创建不可变的Set集合"张三", "李四", "王五", "赵六"*/// 细节:// 当我们要获取一个不可变的Set集合时,里面的参数一定要保证唯一性//一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作Set<String> set = Set.of("张三", "张三", "李四", "王五", "赵六"); // 两个"张三"将导致以下代码无法执行for (String s : set) {System.out.println(s);}System.out.println("---------------------");Iterator<String> it = set.iterator();while (it.hasNext()) {String s = it.next();System.out.println(s);}System.out.println("---------------------");//set.remove("王五"); // 报错} }
package a11_不可变集合;import java.util.HashMap; import java.util.Map; import java.util.Set;public class a04_创建Map的不可变集合且键值对的数量超过10个 {public static void main(String[] args) {/*创建Map的不可变集合,键值对的数量超过10个*///1.创建一个普通的Map集合HashMap<String, String> hm = new HashMap<>();hm.put("张三", "南京");hm.put("李四", "北京");hm.put("王五", "上海");hm.put("赵六", "北京");hm.put("孙七", "深圳");hm.put("周八", "杭州");hm.put("吴九", "宁波");hm.put("郑十", "苏州");hm.put("刘一", "无锡");hm.put("陈二", "嘉兴");hm.put("aaa", "111");//2.利用上面的数据来获取一个不可变的集合//获取到所有的键值对对象(Entry对象)Set<Map.Entry<String, String>> entries = hm.entrySet();//把entries变成一个数组Map.Entry[] arr1 = new Map.Entry[0];//toArray方法在底层会比较集合的长度跟数组的长度两者的大小//如果集合的长度 > 数组的长度 :数据在数组中放不下,此时会根据实际数据的个数,重新创建数组//如果集合的长度 <= 数组的长度:数据在数组中放的下,此时不会创建新的数组,而是直接用Map.Entry[] arr2 = entries.toArray(arr1);//不可变的map集合Map map = Map.ofEntries(arr2);map.put("bbb", "222"); // 报错//简化Map<Object, Object> map1 = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));map1.put("bbb", "222"); // 报错//再简化Map<String, String> map2 = Map.copyOf(hm);map2.put("bbb", "222"); // 报错} }
总结: 不可变集合的特点?定义完成后不可以修改,或者添加、删除 如何创建不可变集合?List、Set、Map 接口中,都存在 of 方法可以创建不可变集合 三种方式的细节List:直接用Set:元素不能重复Map:元素不能重复、键值对数量最多是 10 个。超过 10 个用 ofEntries 方法
Stream流
1.初爽Stream流
package a01_初爽Stream流;import java.util.ArrayList;public class Test {public static void main(String[] args) {/*创建集合添加元素,完成以下需求:1.把所有以“张”开头的元素存储到新集合中2.把“张”开头的,长度为3的元素再存储到新集合中3.遍历打印最终结果*/ArrayList<String> list1 = new ArrayList<>();list1.add("张无忌");list1.add("周芷若");list1.add("赵敏");list1.add("张强");list1.add("张三丰");// //1.把所有以“张”开头的元素存储到新集合中 // ArrayList<String> list2 = new ArrayList<>(); // for (String name : list1) { // if(name.startsWith("张")){ // list2.add(name); // } // } // //2.把“张”开头的,长度为3的元素再存储到新集合中 // ArrayList<String> list3 = new ArrayList<>(); // for (String name : list2) { // if(name.length() == 3){ // list3.add(name); // } // } // //3.遍历打印最终结果 // for (String name : list3) { // System.out.println(name); // }//使用Stream流简化list1.stream().filter(name->name.startsWith("张")).filter(name -> name.length() == 3).forEach(name-> System.out.println(name));} }
2.Stream流的思想和获取Stream流
Stream 流的作用结合了 Lambda 表达式,简化集合、数组的操作 Stream 流的使用步骤:先得到一条 Stream 流(流水线),并把数据放上去利用 Stream 流中的 API 进行各种操作过滤、转换 - 中间方法:方法调用完毕之后,还可以调用其他方法统计、打印 - 终结方法:最后一步,调用完毕之后,不能调用其他方法Stream 流的使用步骤: 1.先得到一条 Stream 流(流水线),并把数据放上去 获取方式 方法名 说明 单列集合 default Stream<E> stream() Collection 中的默认方法 双列集合 无 无法直接使用 stream 流 数组 public static <T> Stream<T> stream(T[] array) Arrays 工具类中的静态方法 一堆零散数据 public static<T> Stream<T> of(T... values) Stream 接口中的静态方法2.使用中间方法对流水线上的数据进行操作 3.使用终结方法对流水线上的数据进行操作
单列集合获取Stream流
package a02_Stream流的思想和获取Stream流;import java.util.ArrayList; import java.util.Collections;public class a01_单列集合获取Stream流 {public static void main(String[] args) {//1.单列集合获取Stream流ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "a", "b", "c", "d", "e"); // //获取到一条流水线,并把集合中的数据放到流水线上 // Stream<String> stream1 = list.stream(); // //使用终结方法打印一下流水线上的所有数据 // stream1.forEach(new Consumer<String>() { // @Override // public void accept(String s) { // //s:依次表示流水线上的每一个数据 // System.out.println(s); // } // });// 简化list.stream().forEach(s -> System.out.println(s));} }
双列集合获取Stream流
package a02_Stream流的思想和获取Stream流;import java.util.HashMap;public class a02_双列集合获取Stream流 {public static void main(String[] args) { // 双列集合 无法直接使用 stream 流//1.创建双列集合HashMap<String,Integer> hm = new HashMap<>();//2.添加数据hm.put("aaa",111);hm.put("bbb",222);hm.put("ccc",333);hm.put("ddd",444);//3.第一种获取stream流(操作键)hm.keySet().stream().forEach(s -> System.out.println(s));//4.第二种获取stream流(操作键值对)hm.entrySet().stream().forEach(s-> System.out.println(s));} }
数组获取Stream流
package a02_Stream流的思想和获取Stream流;import java.util.Arrays;public class a03_数组获取Stream流 {public static void main(String[] args) { // 数组 public static <T> Stream<T> stream(T[] array) Arrays 工具类中的静态方法//1.创建数组int[] arr1 = {1,2,3,4,5,6,7,8,9,10};String[] arr2 = {"a","b","c"};//2.获取stream流Arrays.stream(arr1).forEach(s-> System.out.println(s));System.out.println("========================");Arrays.stream(arr2).forEach(s-> System.out.println(s));System.out.println("========================");//注意: //Stream接口中静态方法of的细节 //方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组 //但是数组必须是引用数据类型的,如果传递基本数据类型的,是会把整个数组当做一个元素,放到Stream当中。 Stream.of(arr1).forEach(s-> System.out.println(s));//[I@4629346} }
一堆零散数据获取Stream流
package a02_Stream流的思想和获取Stream流;import java.util.stream.Stream;public class a04_一堆零散数据获取Stream流 {public static void main(String[] args) {//一堆零散数据 public static<T> Stream<T> of(T... values) Stream 接口中的静态方法Stream.of(1,2,3,4,5).forEach(s-> System.out.println(s));Stream.of("a","b","c","d","e").forEach(s-> System.out.println(s));} }
3.Stream 流的中间方法
名称 说明
Stream<T> filter(Predicate<? super T> predicate) 过滤
Stream<T> limit(long maxSize) 获取前几个元素
Stream<T> skip(long n) 跳过前几个元素
Stream<T> distinct() 元素去重,依赖 (hashCode 和 equals 方法)
static <T> Stream<T> concat(Stream a, Stream b) 合并 a 和 b 两个流为一个流
Stream<R> map(Function<T, R> mapper) 转换流中的数据类型
注意 1:中间方法,返回新的 Stream 流,原来的 Stream 流只能使用一次,建议使用链式编程
注意 2:修改 Stream 流中的数据,不会影响原来集合或者数组中的数据
过滤_获取_跳过
package a03_Stream流的中间方法;import java.util.ArrayList; import java.util.Collections; import java.util.stream.Stream;public class a01_过滤_获取_跳过 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");//filter 过滤 把张开头的留下,其余数据过滤不要/*list.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {//如果返回值为true,表示当前数据留下//如果返回值为false,表示当前数据舍弃不要return s.startsWith("张");}}).forEach(s -> System.out.println(s));*/Stream<String> stream1 = list.stream().filter(s -> s.startsWith("张"));Stream<String> stream2 = stream1.filter(s -> s.length() == 3);stream2.forEach(s -> System.out.println(s));// Stream<String> stream3 = stream1.filter(s -> s.length() == 3); // 报错 stream1流已关闭// 获取前几个元素list.stream().limit(3).forEach(s -> System.out.println(s));// 跳过前几个元素list.stream().skip(4).forEach(s -> System.out.println(s));//课堂练习://获取 "张强", "张三丰", "张翠山"//第一种思路://先获取前面6个元素 "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山",//然后跳过前面3个元素//list.stream().limit(6).skip(3).forEach(s -> System.out.println(s));//第二种思路://先跳过3个元素:"张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤"//然后再获取前面3个元素:"张强", "张三丰", "张翠山"//list.stream().skip(3).limit(3).forEach(s -> System.out.println(s));} }
去重_合并
package a03_Stream流的中间方法;import java.util.ArrayList; import java.util.Collections; import java.util.stream.Stream;public class a02_去重_合并 {public static void main(String[] args) {/*distinct 元素去重,依赖(hashCode和equals方法)concat 合并a和b两个流为一个流注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据*/ArrayList<String> list1 = new ArrayList<>();Collections.addAll(list1, "张无忌","张无忌","张无忌", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");ArrayList<String> list2 = new ArrayList<>();Collections.addAll(list2, "周芷若", "赵敏");// distinct 元素去重list1.stream().distinct().forEach(s -> System.out.println(s));// concat 合并Stream.concat(list1.stream(),list2.stream()).forEach(s -> System.out.println(s));} }
类型转换
package a03_Stream流的中间方法;import java.util.ArrayList; import java.util.Collections; import java.util.function.Function;public class a03_类型转换 {public static void main(String[] args) {/*map 转换流中的数据类型注意1:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程注意2:修改Stream流中的数据,不会影响原来集合或者数组中的数据*/ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "张无忌-15", "周芷若-14", "赵敏-13", "张强-20", "张三丰-100", "张翠山-40", "张良-35", "王二麻子-37", "谢广坤-41");//需求:只获取里面的年龄并进行打印//String->int//第一个类型:流中原本的数据类型//第二个类型:要转成之后的类型//apply的形参s:依次表示流里面的每一个数据//返回值:表示转换之后的数据//当map方法执行完毕之后,流上的数据就变成了整数//所以在下面forEach当中,s依次表示流里面的每一个数据,这个数据现在就是整数了list.stream().map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {String[] arr = s.split("-");String ageString = arr[1];int age = Integer.parseInt(ageString);return age;}}).forEach(s-> System.out.println(s));//简化list.stream().map(s-> Integer.parseInt(s.split("-")[1])).forEach(s-> System.out.println(s));} }
4.Stream流终结方法详解
Stream 流的终结方法 名称 说明 void forEach(Consumer action) 遍历 long count() 统计 toArray() 收集流中的数据,放到数组中 collect(Collector collector) 收集流中的数据,放到集合中
遍历_统计_收集并放到数组
package a04_Stream流终结方法详解;import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.function.IntFunction;public class a01_遍历_统计_收集并放到数组 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");//forEach 遍历//Consumer的泛型:表示流中数据的类型//accept方法的形参s:依次表示流里面的每一个数据//方法体:对每一个数据的处理操作(打印)/*list.stream().forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});*/list.stream().forEach(s -> System.out.println(s));// count() 统计//long count = list.stream().count();//System.out.println(count);//toArray() 收集流中的数据,放到数组中//IntFunction的泛型:具体类型的数组//apply的形参:流中数据的个数,要跟数组的长度保持一致//apply的返回值:具体类型的数组//方法体:就是创建数组//toArray方法的参数的作用:负责创建一个指定类型的数组//toArray方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中//toArray方法的返回值:是一个装着流里面所有数据的数组String[] arr = list.stream().toArray(new IntFunction<String[]>() {@Overridepublic String[] apply(int value) {return new String[value];}});System.out.println(Arrays.toString(arr));//简化String[] arr2 = list.stream().toArray(value -> new String[value]);System.out.println(Arrays.toString(arr2));} }
收集并放到集合
package a04_Stream流终结方法详解;import java.util.*; import java.util.function.Function; import java.util.stream.Collectors;public class a02_收集并放到集合 {public static void main(String[] args) { // collect(Collector collector) 收集流中的数据,放到集合中(List Set Map)ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "张无忌-男-15", "周芷若-女-14", "赵敏-女-13", "张强-男-20","张三丰-男-100", "张翠山-男-40", "张良-男-35", "王二麻子-男-37", "谢广坤-男-41");//收集List集合当中//需求://我要把所有的男性收集起来List<String> newList1 = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toList());System.out.println(newList1);//收集Set集合当中 可去重//需求://我要把所有的男性收集起来Set<String> newList2 = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toSet());System.out.println(newList2);//收集Map集合当中//谁作为键,谁作为值.//我要把所有的男性收集起来//键:姓名。 值:年龄 // 注意点: // 如果我们要收集到 Map 集合当中,键不能重复,否则会报错Map<String, Integer> map = list.stream().filter(s -> "男".equals(s.split("-")[1]))// toMap // 参数一:表示键的生成规则 // 参数二:表示值的生成规则// 参数一 // Function 泛型一:表示流中每一个数据的类型 // Function 泛型二:表示 Map 集合中键的数据类型 // 方法 apply 形参:依次表示流里面的每一个数据 // 方法体:生成键的代码 // 返回值:已经生成的键// 参数二 // Function 泛型一:表示流中每一个数据的类型 // 泛型二:表示 Map 集合中值的数据类型 // 方法 apply 形参:依次表示流里面的每一个数据 // 方法体:生成值的代码 // 返回值:已经生成的值.collect(Collectors.toMap(new Function<String, String>() {@Overridepublic String apply(String s) {//张无忌-男-15return s.split("-")[0];}}, new Function<String, Integer>() {@Overridepublic Integer apply(String s) {return Integer.parseInt(s.split("-")[2]);}}));//简化Map<String, Integer> map2 = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toMap(s -> s.split("-")[0],s -> Integer.parseInt(s.split("-")[2])));System.out.println(map2);} }
Stream流总结 1.Stream 流的作用结合了 Lambda 表达式,简化集合、数组的操作 2.Stream 的使用步骤获取 Stream 流对象使用中间方法处理数据使用终结方法处理数据 3.如何获取 Stream 流对象单列集合:Collection 中的默认方法 stream双列集合:不能直接获取数组:Arrays 工具类型中的静态方法 stream一堆零散的数据:Stream 接口中的静态方法 of 4.常见方法中间方法:filter, limit, skip, distinct, concat, map终结方法:forEach, count, collect
5.综合练习
数字过滤
package a05_综合练习;import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors;public class a01_数字过滤 {public static void main(String[] args) {/*定义一个集合,并添加一些整数 1,2,3,4,5,6,7,8,9,10过滤奇数,只留下偶数。并将结果保存起来*///1. 定义一个集合ArrayList<Integer> list = new ArrayList<>();//2.添加一些整数Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);//3.过滤奇数,只留下偶数//进行判断,如果是偶数,返回true 保留List<Integer> newList = list.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());//4.打印集合System.out.println(newList);} }
字符串过滤并收集
package a05_综合练习;import java.util.ArrayList; import java.util.Map; import java.util.stream.Collectors;public class a02_字符串过滤并收集 {public static void main(String[] args) {/*练习:创建一个ArrayList集合,并添加以下字符串,字符串中前面是姓名,后面是年龄"zhangsan,23""lisi,24""wangwu,25"保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值*///1.创建一个ArrayList集合ArrayList<String> list = new ArrayList<>();//2.添加以下字符串list.add("zhangsan,23");list.add("lisi,24");list.add("wangwu,25");//3.保留年龄大于等于24岁的人 // list.stream() // .filter(s -> Integer.parseInt(s.split(",")[1]) >= 24) // .collect(Collectors.toMap(new Function<String, String>() { // @Override // public String apply(String s) { // return null; // } // }, new Function<String, Integer>() { // @Override // public Integer apply(String s) { // return null; // } // }));//简化Map<String, Integer> map = list.stream().filter(s -> Integer.parseInt(s.split(",")[1]) >= 24).collect(Collectors.toMap(s -> s.split(",")[0],s -> Integer.parseInt(s.split(",")[1])));System.out.println(map);} }
自定义对象过滤并收集
package a05_综合练习;import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream;public class a03_自定义对象过滤并收集 {public static void main(String[] args) {/*现在有两个 ArrayList 集合,分别存储 6 名男演员的名字和年龄以及 6 名女演员的名字和年龄。姓名和年龄中间用逗号隔开。比如:张三,23要求完成如下的操作:1,男演员只要名字为 3 个字的前两人2,女演员只要姓杨的,并且不要第一个3,把过滤后的男演员姓名和女演员姓名合并到一起4,将上一步的演员姓名封装成 Actor 对象。5,将所有的演员对象都保存到 List 集合中。备注:演员类 Actor,属性有:name,age男演员: "蔡坤坤,24" , "叶峋咸,23", "刘不甜,22", "吴签,24", "谷嘉,30", "肖梁梁,27"女演员: "赵小颖,35" , "杨颖,36", "高元元,43", "张天天,31", "刘诗,35", "杨小幂,33"*///1.创建两个ArrayList集合ArrayList<String> manList = new ArrayList<>();ArrayList<String> womenList = new ArrayList<>();//2.添加数据Collections.addAll(manList, "蔡坤坤,24", "叶峋咸,23", "刘不甜,22", "吴签,24", "谷嘉,30", "肖梁梁,27");Collections.addAll(womenList, "赵小颖,35", "杨颖,36", "高元元,43", "张天天,31", "刘诗,35", "杨小幂,33");//3.男演员只要名字为3个字的前两人Stream<String> stream1 = manList.stream().filter(s -> s.split(",")[0].length() == 3).limit(2);//4.女演员只要姓杨的,并且不要第一个Stream<String> stream2 = womenList.stream().filter(s -> s.split(",")[0].startsWith("杨")).skip(1);//5.把过滤后的男演员姓名和女演员姓名合并到一起//演员信息封装成Actor对象。//String -> Actor对象(类型转换) // Stream.concat(stream1,stream2).map(new Function<String, Actor>() { // @Override // public Actor apply(String s) { // //"赵小颖,35" // String name = s.split(",")[0]; // int age = Integer.parseInt(s.split(",")[1]); // return new Actor(name,age); // } // }).forEach(s -> System.out.println(s));List<Actor> list = Stream.concat(stream1, stream2).map(s -> new Actor(s.split(",")[0], Integer.parseInt(s.split(",")[1]))).collect(Collectors.toList());System.out.println(list);} }
方法引用
1.方法引用概述
方法引用 把已经有的方法拿过来用,当做函数式接口中抽象方法的方法体 1.引用处必须是函数式接口 2.被引用的方法必须已经存在 3.被引用方法的形参和返回值需要跟抽象方法保持一致 4.被引用方法的功能要满足当前需求
package a01_方法引用概述;import java.util.Arrays;public class Test {public static void main(String[] args) {//需求:创建一个数组,进行倒序排列Integer[] arr = {3, 5, 4, 1, 6, 2};//匿名内部类/*Arrays.sort(arr, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}});*///lambda表达式//因为第二个参数的类型Comparator是一个函数式接口才能用lambda表达式/*Arrays.sort(arr, (Integer o1, Integer o2)->{return o2 - o1;});System.out.println(Arrays.toString(arr));*///lambda表达式简化格式//Arrays.sort(arr, (o1, o2)->o2 - o1 );//方法引用//表示引用Test类里面的subtraction方法//把这个方法当做抽象方法的方法体Arrays.sort(arr, Test::subtraction);System.out.println(Arrays.toString(arr));}//可以是Java已经写好的,也可以是一些第三方的工具类public static int subtraction(int num1, int num2) {return num2 - num1;} }
总结 1. 什么是方法引用?把已经存在的方法拿过来用,当做函数式接口中抽象方法的方法体 2. :: 是什么符号?方法引用符 3.方法引用时要注意什么?需要有函数式接口被引用方法必须已经存在被引用方法的形参和返回值需要跟抽象方法保持一致被引用方法的功能要满足当前的需求
方法引用的分类1.引用静态方法2.引用成员方法引用其他类的成员方法引用本类的成员方法引用父类的成员方法3.引用构造方法4.其他调用方式使用类名引用成员方法引用数组的构造方法
2.引用静态方法
package a02_引用静态方法;import java.util.ArrayList; import java.util.Collections;public class Test {public static void main(String[] args) {/*方法引用(引用静态方法)格式类::方法名需求:集合中有以下数字,要求把它们都变成int类型"1","2","3","4","5"*///1.创建集合并添加元素ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "1","2","3","4","5");//2.把它们都变成int类型/*list.stream().map(new Function<String, Integer>() {@Overridepublic Integer apply(String s) {int i = Integer.parseInt(s);return i;}}).forEach(s -> System.out.println(s));*///使用方法引用//1.方法需要已经存在//2.方法的形参和返回值需要跟抽象方法的形参和返回值保持一致//3.方法的功能需要把形参的字符串转换成整数list.stream().map(Integer::parseInt).forEach(s-> System.out.println(s));} }
3.引用其他类的成员方法
引用成员方法 格式:对象::成员方法 其他类:其他类对象::方法名 本类:this::方法名 父类:super::方法名
package a03_引用其他类的成员方法;import java.util.ArrayList; import java.util.Collections;public class Test1 {public static void main(String[] args) {/*方法引用(引用成员方法)格式其他类:其他类对象::方法名本类:this::方法名(引用处不能是静态方法)父类:super::方法名(引用处不能是静态方法)需求:集合中有一些名字,按照要求过滤数据数据:"张无忌","周芷若","赵敏","张强","张三丰"要求:只要以张开头,而且名字是3个字的*///1.创建集合ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "张无忌","周芷若","赵敏","张强","张三丰");//3.过滤数据(只要以张开头,而且名字是3个字的)//list.stream().filter(s->s.startsWith("张")).filter(s->s.length() == 3).forEach(s-> System.out.println(s));// list.stream().filter(new Predicate<String>() { // @Override // public boolean test(String s) { // return s.startsWith("张") && s.length() == 3; // } // }).forEach(s-> System.out.println(s));//使用方法引用StringOperation so = new StringOperation();list.stream().filter(so::stringJudge).forEach(s-> System.out.println(s));} }
package a03_引用其他类的成员方法;public class StringOperation {public boolean stringJudge(String s){return s.startsWith("张") && s.length() == 3;} }
4.引用本类或父类的成员方法
package a04_引用本类或父类的成员方法;import javax.swing.*; import java.awt.*;//需求: //点击GO,打印// 引用父类 public class LoginJFrame extends MyJFrame { // 引用本类 //public class LoginJFrame extends JFrame {JButton go = new JButton("Go");public LoginJFrame() {//设置图标setIconImage(Toolkit.getDefaultToolkit().getImage("myfunction\\image\\logo.jpg"));//设置界面initJframe();//添加组件initView();//界面显示出来this.setVisible(true);}//添加组件public void initView() {JLabel image = new JLabel(new ImageIcon("myfunction\\image\\kit.jpg"));image.setBounds(100, 50, 174, 174);this.getContentPane().add(image);go.setFont(new Font(null, 1, 20));go.setBounds(120, 274, 150, 50);go.setBackground(Color.WHITE);// 引用本类 // go.addActionListener(this::method); // 引用父类go.addActionListener(super::method);this.getContentPane().add(go);}//设置界面public void initJframe() {//设置标题this.setTitle("随机点名器");//设置大小this.setSize(400, 500);//设置关闭模式this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置窗口无法进行调节this.setResizable(false);//界面居中this.setLocationRelativeTo(null);//取消内部默认居中放置this.setLayout(null);//设置背景颜色this.getContentPane().setBackground(Color.white);this.setAlwaysOnTop(true);//置顶}// 引用本类 // public void method(ActionEvent e) { // System.out.println("go按钮被点击了"); // } }
package a04_引用本类或父类的成员方法;import javax.swing.*; import java.awt.event.ActionEvent;public class MyJFrame extends JFrame {public void method(ActionEvent e) {System.out.println("go按钮被点击了");} }
5.引用构造方法
方法引用的规则: 1.需要有函数式接口 2.被引用的方法必须已经存在 3.被引用方法的形参和返回值,需要跟抽象方法的形参返回值保持一致 4.被引用方法的功能需要满足当前的需求
package a05_引用构造方法;import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors;public class Test {public static void main(String[] args) {/*方法引用(引用构造方法)格式类名::new目的:创建这个类的对象需求:集合里面存储姓名和年龄,要求封装成Student对象并收集到List集合中*///1.创建集合对象ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "张无忌,15", "周芷若,14", "赵敏,13", "张强,20", "张三丰,100", "张翠山,40", "张良,35", "王二麻子,37", "谢广坤,41");//3.封装成Student对象并收集到List集合中//String --> Student // List<Student> newList = list.stream().map(new Function<String, Student>() { // @Override // public Student apply(String s) { // String[] arr = s.split(","); // String name = arr[0]; // int age = Integer.parseInt(arr[1]); // return new Student(name, age); // } // }).collect(Collectors.toList()); // System.out.println(newList);//引用构造方法List<Student> newList2 = list.stream().map(Student::new).collect(Collectors.toList());System.out.println(newList2);} }
package a05_引用构造方法;public class Student {private String name;private int age;public Student() {}//写一个新的构造方法public Student(String str) {String[] arr = str.split(",");this.name = arr[0];this.age = Integer.parseInt(arr[1]);}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;} }
6.类名引用成员方法
方法引用的规则: 1.需要有函数式接口 2.被引用的方法必须已经存在 3.被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致。 4.被引用方法的功能需要满足当前的需求抽象方法形参的详解: 第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法在 Stream 流当中,第一个参数一般都表示流里面的每一个数据。假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用 String 这个类中的方法 第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法局限性:不能引用所有类中的成员方法。是跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法。
package a06_类名引用成员方法;import java.util.ArrayList; import java.util.Collections;public class Test {public static void main(String[] args) {/*方法引用(类名引用成员方法)格式类名::成员方法需求:集合里面一些字符串,要求变成大写后进行输出*///1.创建集合对象ArrayList<String> list = new ArrayList<>();//2.添加数据Collections.addAll(list, "aaa", "bbb", "ccc", "ddd");//3.变成大写后进行输出//String --> String/*list.stream().map(new Function<String, String>() {@Overridepublic String apply(String s) {return s.toUpperCase();}}).forEach(s -> System.out.println(s));*///类名引用成员方法//map(String::toUpperCase)//拿着流里面的每一个数据,去调用String类中的toUpperCase方法,方法的返回值就是转换之后的结果。list.stream().map(String::toUpperCase).forEach(s -> System.out.println(s));} }
7.引用数组的构造方法
package a07_引用数组的构造方法;import java.util.ArrayList; import java.util.Arrays; import java.util.Collections;public class Test {public static void main(String[] args) {/*方法引用(数组的构造方法)格式数据类型[]::new目的:创建一个指定类型的数组需求:集合中存储一些整数,收集到数组当中细节:数组的类型,需要跟流中数据的类型保持一致。*///1.创建集合并添加元素ArrayList<Integer> list = new ArrayList<>();Collections.addAll(list, 1, 2, 3, 4, 5);//2.收集到数组当中 // Integer[] arr = list.stream().toArray(new IntFunction<Integer[]>() { // @Override // public Integer[] apply(int value) { // return new Integer[value]; // } // });// 引用数组的构造方法Integer[] arr = list.stream().toArray(Integer[]::new);//3.打印System.out.println(Arrays.toString(arr));} }
总结: 1.什么是方法引用?把已经存在的方法拿过来用,当做函数式接口中抽象方法的方法体 2.::是什么符号?方法引用符 3.方法引用时要注意什么?需要有函数式接口被引用方法必须已经存在被引用方法的形参与返回值需要跟抽象方法保持一致被引用方法的功能要满足当前的需求1.引用静态方法类名::静态方法 2.引用成员方法对象::成员方法this::成员方法super::成员方法 3.引用构造方法类名::new 4.使用类名引用成员方法类名::成员方法局限性:不能引用所有类中的成员方法。如果抽象方法的第一个参数是 A 类型的,只能引用 A 类中的方法 5.引用数组的构造方法数据类型 []::new
练习
1.转成自定义对象并收集到数组
package a08_练习;import a05_引用构造方法.Student;import java.util.ArrayList; import java.util.Arrays; import java.util.Collections;public class a01_转成自定义对象并收集到数组 {public static void main(String[] args) {/*需求:集合中存储一些字符串的数据,比如:张三,23。收集到Student类型的数组当中*///1.创建集合并添加元素ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "张无忌,15", "周芷若,14", "赵敏,13", "张强,20", "张三丰,100", "张翠山,40", "张良,35", "王二麻子,37", "谢广坤,41");//2.先把字符串变成Student对象,然后再把Student对象收集起来Student[] arr = list.stream().map(Student::new).toArray(Student[]::new);//打印数组System.out.println(Arrays.toString(arr));} }
2.获取部分属性并收集到数组
package a08_练习;import java.util.ArrayList; import java.util.Arrays;public class a02_获取部分属性并收集到数组 {public static void main(String[] args) {/** 需求:* 创建集合添加学生对象* 学生对象属性: name, age* 要求:* 获取姓名并放到数组当中* 使用方法引用完成** 技巧:* 1.现在有没有一个方法符合我当前的需求* 2.如果有这样的方法,这个方法是否满足引用的规则* 静态:类名::方法名* 成员方法* 构造方法:类名::new** *///1.创建集合ArrayList<Student> list = new ArrayList<>();//2.添加元素list.add(new Student("zhangsan", 23));list.add(new Student("lisi", 24));list.add(new Student("wangwu", 25));//3.获取姓名并放到数组当中String[] arr = list.stream().map(Student::getName).toArray(String[]::new);/*String[] arr = list.stream().map(new Function<Student, String>() {@Overridepublic String apply(Student student) {return student.getName();}}).toArray(String[]::new);*/System.out.println(Arrays.toString(arr));} }
异常
1.异常体系介绍
异常:异常就是代表程序出现的问题 误区:不是让我们以后不出异常,而是程序出了异常之后,该如何处理Exception包含:1.RuntimeException:...2.其他异常说明:Exception:叫做异常,代表程序可能出现的问题。我们通常会用 Exception 以及他的子类来封装程序出现的问题。运行时异常:RuntimeException 及其子类,编译阶段不会出现异常提醒。运行时出现的异常(如:数组索引越界异常)编译时异常:编译阶段就会出现异常提醒的。(如:日期解析异常)总结: 异常是什么?程序中可能出现的问题 异常体系的最上层父类是谁?异常分为几类?父类: Exception。异常分为两类:编译时异常、运行时异常 编译时异常和运行时异常的区别?编译时异常: 没有继承 RuntimeExcpetion 的异常,直接继承于 Excpetion。编译阶段就会错误提示运行时异常: RuntimeException 本身和子类。编译阶段没有错误提示,运行时出现的
2.编译时异常和运行时异常
Exception:叫做异常,代表程序可能出现的问题。我们通常会用 Exception 以及他的子类来封装程序出现的问题。 (Javac命令)编译时异常:编译阶段就会出现异常提醒的。(如:日期解析异常) (Java命令)运行时异常:RuntimeException 及其子类,编译阶段不会出现异常提醒。运行时出现的异常(如:数组索引越界异常)
//编译时异常(在编译阶段,必须要手动处理,否则代码报错) String time = "2030年1月1日"; SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); Date date = sdf.parse(time); System.out.println(date);//运行时异常(在编译阶段是不需要处理的,是代码运行时出现的异常) int[] arr = {1,2,3,4,5}; System.out.println(arr[10]);//ArrayIndexOutOfBoundsException
运行时异常和编译时异常的区别? 编译时异常:除了 RuntimeExcpetion 和他的子类,其他都是编译时异常。编译阶段需要进行处理,作用在于提醒程序员。 运行时异常:RuntimeException 本身和所有子类,都是运行时异常。编译阶段不报错,是程序运行时出现的。一般是由于参数传递错误带来的问题
3.异常在代码中的两个作用
package a03_异常在代码中的两个作用;public class Test1 {public static void main(String[] args) {/*异常作用一:异常是用来查询bug的关键参考信息异常作用二:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况*/Student[] arr = new Student[3];// null null nullString name = arr[0].getName();// 空指针异常System.out.println(name);} }
package a03_异常在代码中的两个作用;public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {if(age < 18 || age > 40){//System.out.println("年龄超出范围");throw new RuntimeException();}else{this.age = age;}} }
package a03_异常在代码中的两个作用;public class Test2 {public static void main(String[] args) {/*异常作用一:异常是用来查询bug的关键参考信息异常作用二:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况*/Student2 stu = new Student2("张三,23"); // 数组越界异常System.out.println(stu);} }
package a03_异常在代码中的两个作用;public class Test3 {public static void main(String[] args) {/*异常作用一:异常是用来查询bug的关键参考信息异常作用二:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况*///1.创建学生对象Student s1 = new Student();//年龄:(同学)18~40岁s1.setAge(50);//就知道了50赋值失败//选择1: 自己悄悄处理//选择2: 打印在控制台上(默认)} }
package a03_异常在代码中的两个作用;public class Student2 {private String name;private int age;public Student2() {}public Student2(String str) { // "张三,23"String[] arr = str.split("-");arr[0]: 张三,23this.name = arr[0];this.age = Integer.parseInt(arr[1]); // 数组越界异常}public Student2(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;} }
4.JVM虚拟机默认处理异常的方式
异常的处理方式 1.JVM 默认的处理方式 2.自己处理 3.抛出异常JVM 默认的处理方式把异常的名称,异常原因及异常出现的位置等信息输出在了控制台程序停止执行,下面的代码不会再执行了
System.out.println("狂踹瘸子那条好腿"); System.out.println(2/0);//算术异常 ArithmeticException System.out.println("是秃子终会发光"); System.out.println("火鸡味锅巴");
5.try...catch捕获异常
自己处理(捕获异常) 格式: try {可能出现异常的代码; } catch(异常类名 变量名) {异常的处理代码; }好处:当代码出现异常时,可以让程序继续往下执行。
package a05_try_catch捕获异常;public class Test {public static void main(String[] args) {int[] arr = {1, 2, 3, 4, 5, 6};try{//可能出现异常的代码;System.out.println(arr[10]);// 此处出现了异常,程序就会在这里创建一个 ArrayIndexOutOfBoundsException 对象//new ArrayIndexOutOfBoundsException ();// 拿着这个对象到 catch 的小括号中对比,看括号中的变量是否可以接收这个对象// 如果能被接收,就表示该异常就被捕获(抓住),执行 catch 里面对应的代码// 当 catch 里面所有的代码执行完毕,继续执行 try...catch 体后面的其他代码}catch(ArrayIndexOutOfBoundsException e){//如果出现了ArrayIndexOutOfBoundsException异常,我该如何处理System.out.println("索引越界了");}System.out.println("看看我执行了吗?");} }
6.捕获异常灵魂四问
自己处理(捕获异常)灵魂四问:灵魂一问:如果try中没有遇到问题,怎么执行?答:会把 try 里面所有的代码全部执行完毕,不会执行 catch 里面的代码灵魂二问:如果try中可能会遇到多个问题,怎么执行?答:会写多个 catch 与之对应,父类异常需要写在下面灵魂三问:如果try中遇到的问题没有被捕获,怎么执行?答:相当于 try...catch 白写了,当前异常会交给虚拟机处理灵魂四问:如果try中遇到了问题,那么try下面的其他代码还会执行吗?答:不会执行了。try 中遇到问题,直接跳转到对应的 catch,如果没有对应的 catch 与之匹配,则交给虚拟机处理
try中没有问题
package a06_捕获异常灵魂四问;public class a01_try中没有问题 {public static void main(String[] args) { // 灵魂一问:如果 try 中没有遇到问题,怎么执行? // 会把 try 里面所有的代码全部执行完毕,不会执行 catch 里面的代码 // 注意:只有当出现了异常才会执行 catch 里面的代码int[] arr = {1, 2, 3, 4, 5, 6};try{System.out.println(arr[0]); // 1}catch(ArrayIndexOutOfBoundsException e){System.out.println("索引越界了");}System.out.println("看看我执行了吗?"); // 看看我执行了吗?} }
try中有多个问题
package a06_捕获异常灵魂四问;public class a02_try中有多个问题 {public static void main(String[] args) {/*自己处理(捕获异常)灵魂四问:灵魂二问:如果try中可能会遇到多个问题,怎么执行?*/int[] arr = {1, 2, 3, 4, 5, 6};try{System.out.println(arr[10]);//ArrayIndexOutOfBoundsExceptionSystem.out.println(2/0);//ArithmeticException//如果只写一个catch 则会跳过第二个异常 直接执行catch里的代码}catch(ArrayIndexOutOfBoundsException e){System.out.println("索引越界了");}System.out.println("看看我执行了吗?");// 正确写代码方式: // 会写多个 catch 与之对应 // 细节: // 如果我们要捕获多个异常,这些异常中如果存在父子关系的话,那么父类一定要写在下面try{System.out.println(arr[10]);//ArrayIndexOutOfBoundsExceptionSystem.out.println(2/0);//ArithmeticExceptionString s = null;System.out.println(s.equals("abc"));}catch(ArrayIndexOutOfBoundsException e){ // 子类System.out.println("索引越界了");}catch(ArithmeticException e){ // 子类System.out.println("除数不能为0");}catch(NullPointerException e){ // 子类System.out.println("空指针异常");}catch (Exception e){ // 父类System.out.println("Exception");}System.out.println("看看我执行了吗?");// 了解性: // 在 JDK7 之后,我们可以在 catch 中同时捕获多个异常,中间用|进行隔开 // 表示如果出现了 A 异常或者 B 异常的话,采取同一种处理方案 // catch(ArrayIndexOutOfBoundsException | ArithmeticException e)} }
try中遇到的问题没被捕获
package a06_捕获异常灵魂四问;public class a03_try中遇到的问题没被捕获 {public static void main(String[] args) {/*自己处理(捕获异常)灵魂三问:如果try中遇到的问题没有被捕获,怎么执行?相当于try...catch的代码白写了,最终还是会交给虚拟机进行处理。*/int[] arr = {1, 2, 3, 4, 5, 6};try{System.out.println(arr[10]);//ArrayIndexOutOfBoundsException}catch(NullPointerException e){System.out.println("空指针异常");}System.out.println("看看我执行了吗?");} }
try中遇到问题_try下面的代码执行吗
package a06_捕获异常灵魂四问;public class a04_try中遇到问题_try下面的代码执行吗 {public static void main(String[] args) {/*自己处理(捕获异常)灵魂四问:如果try中遇到了问题,那么try下面的其他代码还会执行吗?下面的代码就不会执行了,直接跳转到对应的catch当中,执行catch里面的语句体但是如果没有对应catch与之匹配,那么还是会交给虚拟机进行处理*/int[] arr = {1, 2, 3, 4, 5, 6};try{System.out.println(arr[10]);System.out.println("看看我执行了吗?... try");}catch(ArrayIndexOutOfBoundsException e){System.out.println("索引越界了");}System.out.println("看看我执行了吗?... 其他代码");} }
7.异常中的常见方法
Throwable 的成员方法 方法名称 说明 public String getMessage() 返回此 throwable 的详细消息字符串 public String toString() 返回此可抛出的简短描述 public void printStackTrace() 在底层是利用 System.err.println 进行输出把异常的错误信息以红色字体输出在控制台细节:仅仅是打印信息,不会停止程序运行
package a07_异常中的常见方法;public class Test {public static void main(String[] args) {int[] arr = {1, 2, 3, 4, 5, 6};try {System.out.println(arr[10]);} catch (ArrayIndexOutOfBoundsException e) { // String message = e.getMessage(); // System.out.println(message);//Index 10 out of bounds for length 6// String str = e.toString(); // System.out.println(str);//java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 6//底层用了System.err,红色字体输出e.printStackTrace(); // 最常用 已包含getMessage和toString内容}System.out.println("看看我执行了吗?");//正常的输出语句System.out.println(123); // 正常字体//错误的输出语句(而是用来打印错误信息)System.err.println(123); // 红色字体} }
8.抛出异常
抛出处理 1.throws注意:写在方法定义处,表示声明一个异常,告诉调用者,使用本方法可能会有哪些异常public void 方法()throws 异常类名1,异常类名2...{...}编译时异常:必须要写。运行时异常:可以不写。2.throw注意:写在方法内,结束方法,手动抛出异常对象,交给调用者,方法中下面的代码不再执行了public void 方法(){throw new NullPointerException();}
package a08_抛出异常;public class Test {public static void main(String[] args) {int[] arr = null;int max = 0;try {max = getMax(arr);} catch (NullPointerException e) {System.out.println("空指针异常");} catch (ArrayIndexOutOfBoundsException e) {System.out.println("索引越界异常");}System.out.println(max);}// 运行时期异常不需要手动声明public static int getMax(int[] arr) /*throws NullPointerException,ArrayIndexOutOfBoundsException*/{if(arr == null){//手动创建一个异常对象,并把这个异常交给方法的调用者处理//此时方法就会结束,下面的代码不会再执行了throw new NullPointerException();}if(arr.length == 0){//手动创建一个异常对象,并把这个异常交给方法的调用者处理//此时方法就会结束,下面的代码不会再执行了throw new ArrayIndexOutOfBoundsException();}System.out.println("看看我执行了吗?");int max = arr[0];for (int i = 1; i < arr.length; i++) {if(arr[i] > max){max = arr[i];}}return max;} }
异常总结: 1.虚拟机默认处理异常的方式把异常信息以红色字体打印在控制台,并结束程序 2.捕获:try...catch一般用在调用处,能让代码继续往下运行。 3.抛出:throw throws在方法中,出现异常了。方法就没有继续运行下去的意义了,采取抛出处理。让该方法结束运行并告诉调用者出现了问题。