JavaSE学习笔记——异常处理、集合

Day10

  • 异常处理
    • Java异常
    • 异常
      • 异常体系
    • 异常处理机制
      • 捕获异常
        • try...catch()...
        • 书写格式
      • 抛出异常
        • throw、throws
      • 异常处理原则
      • 自定义异常
      • 方法重写中的异常
      • 练习
  • 集合
    • 概述
    • Collections
      • List:排序操作:
      • 查找、替换
      • 同步控制
      • 其他方法
    • Set
      • HashSet
        • 特点
        • 方法
        • 迭代器
      • TreeSet
        • 特点
        • 方法
        • 自然排序
        • 定制排序
        • 练习
    • List
      • ArrayList
        • 特点
        • 方法
        • listIterator()
      • LinkedList
        • 特点
        • 方法
    • Map
      • HashMap
        • 特点
        • 方法
        • 遍历Map
        • 示例
      • TreeMap
        • 特点
        • 方法
        • 练习
      • Map嵌套

异常处理

Java异常

任何一种程序设计语言设计的程序在运行时都有可能出现错误,例如除数为0,数组下标越界,要读写的文件不存在等等。
捕获错误最理想的是在编译期间,但有的错误只有在运行时才会发生。

对于这些错误,一般有两种解决方法:

  • 遇到错误就终止程序的运行。
  • 程序员在编写程序时,考虑到错误的检测、错误消息的提示,以及错误的处理等。

异常

在Java中,将程序执行中发生的不正常情况称为"异常"。
异常是对问题的描述,将问题封装成类

异常可分为两类:

  • Error:JVM系统内部错误、资源耗尽等严重情况;
  • Exception:其它因编程错误或外部因素导致的问题,例如:
    (1)空指针访问;
    (2)读取的文件不存在;
    (3)网络连接中断。

程序员只能处理Exception,不能处理Error。

例如数组越界异常:

public class Test01{
	public static void main(String[] args) {
      	String friends[]={"lisa","bily","kessy"};
      	for(int i=0;i<5;i++){
           System.out.println(friends[i]); //friends[4]?
        }
		System.out.println("\nthis is the end");
   }
}

程序Test01编译正确,运行结果:
在这里插入图片描述

异常体系

JavaSE学习笔记——异常处理、集合_第1张图片
特点: 异常体系中的所有类都具备可抛性,即都可以被try…catch处理,只有异常体系具备这个特点。

异常分为两种:

  • 编译时被检测的异常(除RuntimeException以外的Exception)。
  • 编译时不被检测的异常,即运行时异常(RuntimeException及其子类)。

异常处理机制

捕获异常

try…catch()…

异常处理是通过try-catch-finally语句实现的,其中finally可有可无。

  • try:
    用try{…}语句块选定可能出现异常的范围,将可能出现异常的代码放在try语句块中。
  • catch (Exceptiontype e):
    处理异常, Exceptiontype e是可能出现的异常类型,不确定时可以使用父类Exception。
  • finally:
    不论在try、catch代码块中是否发生了异常事件,finally块中的语句都会被执行。 finally语句是可选的。
  • 注意:
    (1)如果明确产生异常的类型,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数。
    (2)有多个catch时,按照程序执行的顺序,当捕获第一个异常后,下面的catch不执行,就算有其他异常也不执行。 例如一段程序同时有数组越界异常和空指针异常,当catch首先捕获到数组越界异常后,就不会去捕获空指针异常。

书写格式

try {
	
}catch(){
	
}
-------------------------
try {
	
}finally{
	
}
-------------------------
try {
	需要被检测的代码;
}catch() {
	处理异常的代码;
}finally {
	一定会执行的代码;
}

注意:

  1. finally中一般定义关闭资源的代码,因为资源使用完毕后必须释放。
  2. 只有一种情况finally语句不会执行:当catch语句中有 System.exit(0); 时,退出java系统,jvm结束。

抛出异常

throw、throws

1. 语法格式:
修饰符 返回值类型 方法名() throws xxxException/Exception{…}

2. 注意:
抛出异常后,要在调用该方法时捕获异常,最迟要在main方法上捕获异常,若一直抛出不捕获,该异常抛给JVM,程序将不能处理该异常,但程序可以执行。

2. throw、throws的用法:

  • throws使用在方法声明上,throw使用在方法体内。
  • throws后面接的是异常类,有多个异常类时要用 " , " 隔开;throw后面接的是异常类对象。

当方法内有throw抛出异常时,若在方法内并未进行try catch处理,则必须在方法名上throws该异常类,否则编译失败(RuntimeException除外)。当调用者使用了抛出异常的方法时,有两种处理办法,一是try catch处理异常,二是继续抛出异常。

异常处理原则

  1. 处理方式有两种:try catch(可以解决)或throws(不能解决)。

  2. 当调用到抛出异常的代码时,抛出几个异常就要处理几个异常,即一个try对应多个catch。

  3. 有多个catch时,父类的catch要放在最下面。

  4. catch内要定义有针对性的处理措施,不要简单定义e.printStackTrace()或输出语句,也不要什么都不写。

  5. 当捕获到的异常本功能不能处理时,可以继续在catch内抛出。

    try{
    	throw new MyException();
    }catch(MyException e){
    	throw e;
    }
    

    如果捕获到的异常不属于本功能可能出现的异常,可以将异常转换为与本功能相关的异常之后,再进行处理或抛出。

    try{
    	throw new AException();
    }catch(AException e){
    	throw new BException();
    }
    

自定义异常

1. 自定义异常类:
定义异常类继承Exception或者RuntimeException。

2. 自定义异常信息:
利用父类已有的方法,将异常信息参数父类构造方法。

class MyException extends Exception{
	MyException(String msg){
		super(msg);
	}
}

3. Exception与RuntimeException:

  1. 若自定义的异常类继承了RuntimeException,那么在方法名上可以不抛出异常(因为不抛出,所有在调用代码时可以不使用try catch处理)。
  2. 继承其他Exception异常类时:
    (1)在方法内部将异常捕获并处理(catch)。
    (2)在方法名上将异常抛出。
  3. 继承Exception类时,发生异常的部位不影响之后的程序的运行(jvm会跳过产生异常的部位),
    //通过try catch处理异常;
  4. 继承RuntimeException类时,程序如果发生异常就要立即停止运行,结果是异常部位后面的代码都不能执行(因为后面的代码由于该异常变得没有意义)。
  5. 自定义的异常类内可以定义自己的方法。
  6. 自定义异常时, 如果该异常发生后就无法再继续执行后续代码, 则让自定义异常继承RuntimeException,应该停止程序后, 对代码进行修正。

4. 自定义异常的好处:
(1)将问题进行封装。
(2)将正常流程代码和异常处理代码相分离,便于阅读。

5. 举例:

(1)除数不能为0,java中已经定义过了异常。假设本项目中除数也不能为负数。

package exception;

class MyException extends RuntimeException{
	public static final long serialVersionUID = 1L;
	private double value;
	MyException(String msg) {
		super(msg);
	}
}

class Count{
	//假设在本项目中除数不能为负数
	public static double divide(double a, double b) {
		double c = 0;
		if(b < 0) {
			throw new MyException("除数不能为负数");
		}else{
			c = a/b;
		}
		return c;
	}
}

public class TestDivide {
	public static void main(String[] args) {
		System.out.println(Count.divide(3, -1));
	}
}
/*
Exception in thread "main" exception.MyException: 除数不能为负数
		at test/exception.Count.divide(TestRuntimeException.java:16)
		at test/exception.TestRuntimeException.main(TestRuntimeException.java:26)
*/

(2)在自定义的异常类内定义自己的异常方法。

package exception;

//自定义的异常类内可以定义自己的方法
class MyCustomException extends Exception{
	public static final long serialVersionUID = 1L;
	private double value;
	MyCustomException(String msg) {
		super(msg);
	}
	MyCustomException(String msg, double value) {
		super(msg);
		this.value = value;
	}
	//定义自己的异常方法
	public double getValue() {
		return this.value;
	}
}

class CountValue{
	//假设在本项目中除数不能为负数
	public static double divide(double a, double b) throws MyCustomException{
		double c = 0;
		if(b < 0) {
			throw new MyCustomException("除数不能为负数", b);
		}else{
			c = a/b;
		}
		return c;
	}
}

public class CustomException {
	public static void main(String[] args) {
		try {
			System.out.println(CountValue.divide(3, -1));
		}catch(MyCustomException e) {
			System.out.println("除数不能为负数, 出现错误的数值为: " + e.getValue());
		}
	
	}
}

方法重写中的异常

当子类重写父类方法时: 假设A为父类方法,B为子类中重写的方法
(1)如果B要抛出异常,该异常只能为与A相同的异常或异常的子类。B也可以将异常处理掉,不抛出异常。
(2)若A抛出了多个异常,则B只能抛出与A相同的多个异常或A抛出的异常的子集(可以是A抛出的异常的子类异常)。
(3)如果A没有抛出异常, 则B也不能抛出异常,如果B真的有异常产生, 则必须要使用try catch在内部处理掉,绝对不能抛出。
原则:子类重写的方法不能抛出比父类更大的异常(重写方法的权限要越来越大, 抛出的异常要越来越小)。

package exception;

class ExampleException1 extends Exception{
	public static final long serialVersionUID = 1L;
	ExampleException1(String msg){
		super(msg);
	}
}

class ExampleException2 extends ExampleException1{
	public static final long serialVersionUID = 2L;
	ExampleException2(String msg){
		super(msg);
	}
}

class ExampleException3 extends Exception{
	public static final long serialVersionUID = 3L;
	ExampleException3(String msg){
		super(msg);
	}
}

class A{
	public void show(int a, int b, int c) throws ExampleException1, ExampleException3{//抛出多个异常
		if(a<b) {
			throw new ExampleException1("ExampleException1");
		}
		if(a<c) {
			throw new ExampleException3("ExampleException3");
		}
	}
	public void showInfo() {//没有抛出异常
		System.out.println("No Exception");
	}
}

class B extends A{
	public void show(int a, int b, int c) throws ExampleException1//抛出子集
//	public void show(int a, int b, int c) throws ExampleException3//抛出子集
//	public void show(int a, int b, int c) throws ExampleException1, ExampleException3//抛出子集
//	public void show(int a, int b, int c) throws ExampleException2//抛出父类异常的子类异常
	//ExampleException1的子类,ExampleException3的子类或ExampleException1和ExampleException3的子类
	{
		if(b<c) {
			throw new ExampleException2("ExampleException1");
		}
	}
	public void showInfo(){//子类重写的方法不能抛出异常, 若有异常要内部处理
		try {
			throw new ExampleException3("ExampleException3");//有异常
		}catch(ExampleException3 e) {//内部处理, 不能抛出
			e.printStackTrace();
		}
	}
}

public class InheritExcepion {
	public static void main(String[] args) {
		
	}
}

练习

  1. 描述教师使用电脑上课的过程。
package exception;

//异常类, 描述电脑蓝屏
class BlueScreenException extends Exception{
	public static final long serialVersionUID = 1L;
	BlueScreenException(String msg) {
		super(msg);
	}
}
//异常类, 描述电脑死机
class DeadComputerException extends Exception{
	public static final long serialVersionUID = 2L;
	public DeadComputerException(String msg) {
			super(msg);
	}
}
//异常类, 死机或重启之后还无法运行时, 提交给教师的异常, 
//教师不能处理电脑死机的异常, 因此不能抛出DeadComputerException给教师处理。
class CanNotTeachException extends Exception{
	public static final long serialVersionUID = 3L;
	CanNotTeachException(String msg) {
		super(msg);
	}
}
//电脑类
class Computer{
	private static int state = 0;
	public void run() throws BlueScreenException, DeadComputerException{
		if(state==0) {
			System.out.println("电脑运行");
		}else if(state==1) {
			throw new BlueScreenException("电脑蓝屏");
		}else if(state==2){
			throw new DeadComputerException("电脑死机");
		}
	}
	public void restart() throws BlueScreenException, DeadComputerException{
		System.out.println("重启电脑");
		run();
	}
}

//教师类
class Teacher{
	private String name;
	private Computer comp;
	Teacher(String name){
		this.name = name;
		this.comp = new Computer();
	}
	//教师使用电脑上课
	public void teach() throws CanNotTeachException{
		try{
			comp.run();
		}catch(BlueScreenException e) {
			try {
				System.out.println(e.getMessage());
				comp.restart();
			} catch (BlueScreenException e1) {
				doPractice();
				System.out.println(e1.toString()+"多次, 请更换另一台电脑");
			} catch (DeadComputerException e1) {
				throw new CanNotTeachException(e1.getMessage()+", 请更换另一台电脑");
			}
		}catch(DeadComputerException e) {
			System.out.println(e.getMessage());
			doPractice();
			throw new CanNotTeachException(e.getMessage()+", 请更换另一台电脑");
//			doPractice();//throw与return类似, 结束该方法, 故其后不能再有语句, 因为永远执行不到
		}
		System.out.println("开始上课");
	}
	//布置作业
	public void doPractice() {
		System.out.println("做练习");
	}
}

public class TestComputer {
	public static void main(String[] args) {
		Teacher t = new Teacher("数学老师");
		try {
			t.teach();
		} catch (CanNotTeachException e) {
			System.out.println(e.toString());
		}
	}
}
/*
 * state==0:
 * 		电脑运行
 *		开始上课
 * state==1:
 * 		电脑蓝屏
 *	 	重启电脑
 *		做练习
 *		exception.BlueScreenException: 电脑蓝屏多次, 请更换另一台电脑
 *		开始上课
 * state==2:
 * 		电脑死机
 *		做练习
 *		exception.CanNotTeachException: 电脑死机, 请更换另一台电脑
 */
  1. 计算矩形和圆形的面积。
package exception;

//异常类, 当长、宽、半径出现负数时, 出现异常
class NoSuchGraphException extends RuntimeException{
	public static final long serialVersionUID = 1L;
	NoSuchGraphException(String msg){
		super(msg);
	}
} 

//计算图形面积可以当作一个拓展功能, 用接口实现
interface CountArea{
	double countArea();
}
//也可以继承父类实现
//abstract class CountGraph{
//	abstract double countArea();//不需要传入参数, 因为长和宽、半径是长方形和圆形特有的属性
//}

class Rectangle implements CountArea{
	private double length;
	private double width;
	Rectangle(double length, double width) {
		if(length<=0 || width<=0) {
			throw new NoSuchGraphException("输入数据有误, 不存在这种矩形");
		}
		this.length = length;
		this.width = width;
	}
	@Override
	public double countArea() {
		return length * width;
	}
}

class Circular implements CountArea{
	public static final double PI = 3.14;
	private double radius;
	Circular(double radius){
		if(radius<=0) {
			throw new NoSuchGraphException("输入数据有误, 不存在这种圆形");
		}
		this.radius = radius;
	}
	@Override
	public double countArea() {
		return PI * radius * radius;
	}
}

public class TestGraph {
	public static void main(String[] args) {
		double resR = new Rectangle(3, 4).countArea();
		double resC = new Circular(-4).countArea();
		System.out.println("矩形面积为:\t" + resR + "\n圆形面积为:\t" + resC);
	}
}
/*
Exception in thread "main" exception.NoSuchGraphException: 输入数据有误, 不存在这种圆形
		at test/exception.Circular.(TestGraph.java:41)
			at test/exception.TestGraph.main(TestGraph.java:54)
*/

集合

概述

  • 集合类存放于 java.util 包中,是一个用来存放对象的容器。
  • 集合只能存放对象, 存入基本数据类型时会自动装箱成对应的包装类。
  • 集合存放的是多个对象的引用,对象本身还是放在堆内存中。
  • 集合可以存放不同类型,不限数量的数据类型。

Java 集合可分为 Set、List 和 Map 三种:

  • Set:无序、不可重复。
  • List:有序,可重复。
  • Map:具有映射关系。

集合提供了泛型,Java 集合可以指定存入集合的对象的数据类型。

Collections

  • Collections 是 Set、List 和 Map 等集合的父类接口。
  • Collections 中提供了大量方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法

List:排序操作:

  • reverse(List): 反转 List 中元素的顺序。
  • shuffle(List): 对 List 集合元素进行随机排序。
  • sort(List): 根据元素的自然顺序(字典顺序)对指定 List 集合元素按升序排序。
  • sort(List,Comparator): 根据指定的 Comparator 产生的顺序对 List 集合元素进行排序。
  • swap(List,int, int): 将指定 list 集合中的 i 处元素和 j 处元素进行交换。
package abc;

import java.util.*;

public class TestCollection {
	public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer> ();
		int[] arr = {6, 5, 9, 1, 0, 8, 16, 21, 7, 3, 4, 7};
		for(int i = 0; i < arr.length; i++) {
			list.add(arr[i]);
		}
		System.out.println(list);//[6, 5, 9, 1, 0, 8, 16, 21, 7, 3, 4, 7]
		//反转list
		Collections.reverse(list);
		System.out.println(list);//[7, 4, 3, 7, 21, 16, 8, 0, 1, 9, 5, 6]
		//随机打乱list
		Collections.shuffle(list);
		System.out.println(list);//[9, 1, 21, 3, 7, 4, 6, 7, 8, 0, 16, 5]
		//自然排序
		Collections.sort(list);
		System.out.println(list);//[0, 1, 3, 4, 5, 6, 7, 7, 8, 9, 16, 21]
		//将位置i与位置j上的元素换位
		Collections.swap(list, 2, 4);
		System.out.println(list);//[0, 1, 5, 4, 3, 6, 7, 7, 8, 9, 16, 21]

	}
}

定制排序 sort(List,Comparator) 方法

package abc;

import java.util.*;

public class TreeSetSort {
	public static void main(String[] args) {
		Person p1 = new Person("XiaoMing", 21);
		Person p2 = new Person("LiHua", 23);
		Person p3 = new Person("XiaoGang", 22);
		Person p4 = new Person("MingMing", 24);
		
		List<Person> list = new ArrayList<Person> ();
		Person[] p = {p1, p2, p3, p4};
		
		for(Person per : p) {
			list.add(per);
		}
		
		Collections.sort(list, new Person());
		
		for(Person per : list) {
			System.out.println("name: " + per.name + " age: " + per.age);
		}
	}
	
}

注意:

  • TreeSet实现定制排序时,可以选择在创建TreeSet对象时,传入new Xxx() 对象,来实现定制排序。
  • ArrayList实现定制排序时,不可以通过 List< Object > list = new ArrayList< Object > ();方式,只能通过Collections.sort(list, new Xxx());方式。
  • 其中new Xxx()是实现了Comparator接口(compare方法)的类的对象。

查找、替换

  • Object max(Collection): 根据元素的自然顺序,返回给定集合中的最大元素。
  • Object max(Collection,Comparator): 根据 Comparator 指定的顺序,返回给定集合中的最大元素。
  • Object min(Collection): 根据元素的自然顺序,返回给定集合中的最小元素。
  • Object min(Collection,Comparator): 根据 Comparator 指定的顺序,返回给定集合中的最小元素。
  • int frequency(Collection,Object): 返回指定集合中指定元素的出现次数。
  • boolean replaceAll(List list,Object oldVal,Object newVal): 使用新值替换 List 对象的所有旧值。

同步控制

Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题。
JavaSE学习笔记——异常处理、集合_第2张图片

其他方法

  • boolean retainAll(Collection c): 集合中只保留与集合c相同的元素,即只保留交集元素,c1.retainAll(c2)
  • Object[ ] toArray(): 返回一个包含集合中所有元素的数组(元素类型要相同)。

Set

  • 元素是无序的,即存入顺序和取出顺序不一定一致。
  • 元素不可重复。

HashSet

特点

HashSet 是 Set 接口的典型实现,HashSet 按 Hash 算法来存储集合中的元素。

HashSet 的特点:

  • 元素可以是null。
  • 根据 hashCode 值决定该对象在 HashSet 中的存储位置。
  • HashSet 底层数据结构是哈希表。

HashSet 如何保证存入数据的唯一性?

  • 通过存入元素的两个方法,hashCode()equals() 实现,若元素的hashCode() 值相同,判断equas() 是否为true;若元素的hashCode() 值不同,不会调用equas()

  • 对于HashSet的contains()和remove()方法,都会调用hashCode()和equals()来实现。

    package set;
    
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    class Person{
    	private String name;
    	private int age;
    	Person(String name, int age){
    		this.name = name;
    		this.age = age;
    	}
    	@Override
    	public int hashCode() {
    		System.out.println(this.name + "-----hashCode");
    		return name.hashCode() + this.age*39;//保证哈希值不同
    	}
    	@Override
    	public boolean equals(Object obj) {
    		System.out.println(this.name + "-----equals");
    		if(!(obj instanceof Person)) {
    			throw new RuntimeException();
    		}
    		Person p = (Person)obj;
    		if(this.name.equals(p.name) && this.age == p.age) {
    			return true;
    		}
    		return false;
    	}
    	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;
    	}
    	
    }
    
    public class TestHashSet {
    	public static void main(String[] args) {
    		Set set = new HashSet();
    		set.add(new Person("LiHua", 18));
    		set.add(new Person("LiMing", 18));
    		set.add(new Person("XiaoMing", 19));
    		set.add(new Person("LiHua", 18));
    		set.contains(new Person("LiHua", 18));
    		set.remove(new Person("LiMing", 18));
    		getHashSet(set);
    		/*
    		 *证明存数据时调用了hashCode()
    		LiHua-----hashCode
    		LiMing-----hashCode
    		XiaoMing-----hashCode
    		LiHua-----hashCode
    		计算hashCode()之后发现已经存在该值, 判断equals()
    		LiHua-----equals
    		证明contains()调用了两个方法
    		LiHua-----hashCode
    		LiHua-----equals
    		证明remove调用了两个方法
    		LiMing-----hashCode
    		LiMing-----equals
    		XiaoMing  19
    		LiHua  18
    		*/
    	}
    	public static void getHashSet(Set set) {
    		Iterator it = set.iterator();
    		while(it.hasNext()) {
    			Person p = (Person)it.next();
    			System.out.println(p.getName() + "  " + p.getAge());
    		}
    	}
    }
    

方法

JavaSE学习笔记——异常处理、集合_第3张图片

方法 意义
add(Object o) 添加元素o
addAll(Collection c) 添加集合c中的全部元素
clear() 清空集合中所有元素
contains(Object o) 判断集合中是否包含元素o
containsAll(Collection c) 判断集合中是否包含集合c中的全部元素
hashCode() 计算集合的hashcode值
isEmpty() 判断集合是否为空
iterator() 迭代器
remove(Object o) 移除集合中的元素o
removeAll(Collection c) 移除集合中包含在集合c中的全部元素
size() 计算集合长度
toArray() 将集合转换为Object数组
toArray(T[ ] a) 将集合转换为指定类型数组

迭代器

1. 迭代器Iterator
Iterator 接口主要用于遍历 Collection 集合中的元素,Iterator 对象也被称为迭代器。Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力,即不能使用new Iterator()创建对象。 如果需要创建 Iterator 对象,则必须有一个被迭代的集合,即要使用 集合对象 . Iterator() 创建。

2. Iterator中的方法

方法 意义
hasNext() 判断当前迭代器内是否还有元素,return true if the iterator has more elements.
next() 返回迭代器内的下一个元素

3. 代码

package abc;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class TestHashSet {
	public static void main(String[] args) {
		Set set = new HashSet();
		set.add(1);
		set.add("XiaoMing");
		set.add("China");
		
		//Iterator迭代器遍历
		Iterator it = set.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}
	
}

4. for each迭代

package abc;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class TestHashSet {
	public static void main(String[] args) {
		Set set = new HashSet();
		set.add(1);
		set.add("XiaoMing");
		set.add("China");
		
		//for each迭代遍历
		for(Object o : set) {//set没有定义泛型,存放的数据类型不确定,所有要用Object类型接收
			System.out.println(o);
		}
	}
	
}

TreeSet

特点

  • TreeSet 可以确保集合元素处于排序状态,即按照规定的方式排列元素。
  • TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。
  • TreeSet 底层数据结构是二叉树。

TreeSet 如何保证存入数据的唯一性?

  • 通过CompareTo()Compare() 中的return 0实现,若通过比较之后返回0,则认为两个元素相同。
  • 对于TreeSet的contains()和remove()方法,都会调用CompareTo()或Compare()来实现。

方法

与HashSet相同。

自然排序

自然排序:基本数据类型、String、包装类存入TreeSet 时的默认排序方式,按字母顺序升序排序。

  • 排序:TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序排列
    (1)如果 this > obj,返回正数;
    (2)如果 this < obj,返回负数;
    (3)如果 this = obj,返回 0,则认为这两个对象相等,此时不会存入该数据。
  • 必须放入同样类的对象.(默认会进行排序) 否则可能会发生类型转换异常,我们可以使用泛型来进行限制。

定制排序

定制排序:TreeSet 中存入自己定义的对象时,规定的数据排列方式。

两种实现方法:

  • (1)需要排序的对象所属的类实现Comparable接口,实现compareTo()方法, 使得元素本身具备比较性。
  • (2)定义比较器,传入TreeSet的构造函数中, 使得TreeSet具备比较性。实现方式是:通过自定义比较器类或匿名内部类实现Comparator接口,实现Compare()方法。
package set;

import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

/*
 * 两种方式实现有序
 */
//方法1: 要排序的类实现Comparable接口
class Student implements Comparable{
	private String name;
	private int age;
	Student(String name, int age){
		this.name = name;
		this.age = age;
	}
	@Override
	public int compareTo(Object o) {
		//按照年龄排序
		if(!(o instanceof Student)) {
			throw new RuntimeException();
		}
		Student s = (Student)o;
//		//使用整型包装类完成
//		Integer i1 = this.age;
//		Integer i2 = s.age;
//		int num = i1.compareTo(i2);
//		if(num == 0) {
//			return this.name.compareTo(s.name);
//		}
//		return num;
		if(this.age < s.age) {
			return -1;
		}else if(this.age == s.age) {
			//年龄相同时,不能返回0,会造成姓名不同年龄相同的数据无法存入
			//调用字符串的CompareTo()方法, 若姓名也相同, 则返回0
			return this.name.compareTo(s.name);
		}
		return 1;
	}

	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;
	}
}

//方法2: 其他类(或匿名内部类)实现Comparator()接口
class MyComparator implements Comparator{
	@Override
	public int compare(Object o1, Object o2) {
		//按照姓名排序
		if(!(o1 instanceof Student) || !(o2 instanceof Student)) {
			throw new RuntimeException();
		}
		Student s1 = (Student)o1;
		Student s2 = (Student)o2;
		//使用整型包装类完成
		int num = s1.getName().compareTo(s2.getName());
		if(num == 0) {
			Integer i1 = s1.getAge();
			Integer i2 = s2.getAge();
			return i1.compareTo(i2);
		}
		return num;
	}
	
}

public class TestTreeSet {
	public static void main(String[] args) {
		//方法1
		Set s1 = new TreeSet();
		s1.add(new Student("xx", 18));
		s1.add(new Student("xy", 19));
		s1.add(new Student("xz", 20));
		s1.add(new Student("yz", 18));
		getTreeSet(s1);
		System.out.println("-------");
		//方法2
		Set s2 = new TreeSet(new MyComparator());
		s2.add(new Student("zx", 18));
		s2.add(new Student("vy", 19));
		s2.add(new Student("xz", 20));
		s2.add(new Student("yz", 18));
		getTreeSet(s2);
		/*
		xx  18
		yz  18
		xy  19
		xz  20
		-------
		vy  19
		xz  20
		yz  18
		zx  18
		*/
//		//方法2的匿名内部类实现
//		Set s2 = new TreeSet(new Comparator() {
//			public int compare(Object o1, Object o2) {
//				//按照姓名排序
//				if(!(o1 instanceof Student) || !(o2 instanceof Student)) {
//					throw new RuntimeException();
//				}
//				Student s1 = (Student)o1;
//				Student s2 = (Student)o2;
//				//使用整型包装类完成
//				int num = s1.getName().compareTo(s2.getName());
//				if(num == 0) {
//					Integer i1 = s1.getAge();
//					Integer i2 = s2.getAge();
//					return i1.compareTo(i2);
//				}
//				return num;
//			}
//		});
	}
	
	public static void getTreeSet(Set set) {
		Iterator it = set.iterator();
		while(it.hasNext()) {
			Student s = (Student)it.next();
			System.out.println(s.getName() + "  " + s.getAge());
		}
	}
}

练习

对字符串按照长度排序

package set;

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

/*
 * 对字符串按照长度排序
 */
public class Pratice {
	@SuppressWarnings("unchecked")
	public static void main(String[] args) {
		Set s = new TreeSet(new Comparator() {
			@Override
			public int compare(Object o1, Object o2) {
				String s1 = (String)o1;
				String s2 = (String)o2;
				Integer i1 = s1.length();
				Integer i2 = s2.length();
				int num = i1.compareTo(i2);
				if(num == 0) {
					return s1.compareTo(s2);
				}
				return num;
			}
		});
		
		s.add("abc");
		s.add("a");
		s.add("cd");
		s.add("bc");
		s.add("dcb");
		System.out.println(s);
	}
}

List

  • 元素有序、且可重复,集合中的每个元素都有其对应的顺序索引。

  • 可以通过索引来访问指定位置的集合元素。

  • 默认按元素的添加顺序设置元素的索引。

  • List 调用contains()、remove()方法时(需要判断元素是否相同),依据的是元素的equals()方法。

    注意:元素下标从0开始。

ArrayList

特点

  • 底层数据结构是数组。
  • 查询速度快,但添加和删除较慢。

方法

JavaSE学习笔记——异常处理、集合_第4张图片

方法 意义
add(Object obj) 添加元素
add(int index, Object obj) 在index位置上添加元素
get(int index) 获得index位置上的元素
indexOf(Object obj) 获得指定元素在表中第一次出现时的索引
lastIndexOf(Object obj) 获得指定元素在表中最后一次出现时的索引
remove(int index) 移除index位置上的元素
set(int index, Object obj) 修改index位置的元素为obj
subList(int fromIndex, toIndex) 获得从fromIndex开始到toIndex结束的,长度为(toIndex - fromIndex)的子表,该子表包括fromIndex的元素,不包括toIndex的元素
size() 获得List的长度
clear() 清空List
toArray() 返回一个包含List中所有元素的数组(元素类型要相同)
package abc;

import java.util.ArrayList;
import java.util.List;

public class TestArrayList {
	public static void main(String[] args) {
		List list = new ArrayList();
		//add(Object obj)添加元素
		//add(int index, Object obj)在index位置上添加元素
		list.add(21);//[21]
		list.add(15);//[21, 15]
		list.add(1, 17);//[21, 17, 15]
		list.add(21);//[21, 17, 15, 21]
		//get(int index)获得index位置上的元素
		System.out.println(list.get(1));//17
		//indexOf(Object obj)获得指定元素在表中第一次出现时的索引
		System.out.println(list.indexOf(21));//0
		//lastIndexOf(Object obj)获得指定元素在表中最后一次出现时的索引
		System.out.println(list.lastIndexOf(21));//3
		//remove(int index)移除index位置上的元素
		list.remove(2);//[21, 17, 21]
		//set(int index, Object obj)修改index位置的元素为obj
		list.set(2, 23);//[21, 17, 23]
		//subList(int fromIndex, toIndex)获得从fromIndex开始到toIndex结束的,
		//长度为(toIndex - fromIndex)的子表,该子表包括fromIndex的元素,不包括toIndex的元素
		List sublist = list.subList(0, 2);
		System.out.println(sublist);//[21, 17]
		//size()获得List的长度
		System.out.println(list.size());//3

	}
}

listIterator()

Iterator迭代器在操作集合时,不能使用集合方法(例如add(),remove()等)在迭代时,操作同一个集合。List提供了listIterator()迭代器,可以在迭代时,对集合进行操作。

listIterator()提供的方法 意义
add(E e) 存入元素
hasNext() 正向遍历集合,若还有元素则返回true
hasPrevious() 逆向遍历集合,若还有元素则返回true
next() 返回列表中的下一个元素
previous() 返回列表中的前一个元素
nextIndex() 返回列表中的下一个元素的索引
previousIndex() 返回列表中的前一个元素的索引
remove() 移除由next()或previous()返回的元素
set(E e) 用指定元素代替由next()或previous()返回的元素
package set;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class TestList {
	public static void main(String[] args) {
		//添加元素
		List l = new ArrayList();
		l.add("a");
		l.add("xyz");
		l.add("b");
		l.add("z");
		//迭代输出
		/*
		Iterator it = l.iterator();
		while(it.hasNext()) {
			String s = (String)it.next();
			if(s.equals("b")) {
				l.remove(s);
			}
			System.out.println(s);
		}
		//不可以在迭代时,使用集合方法操作同一个集合
		Exception in thread "main" java.util.ConcurrentModificationException
				at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1009)
				at java.base/java.util.ArrayList$Itr.next(ArrayList.java:963)
				at test/set.TestList.main(TestList.java:22)
		*/
		//使用listIterator()
		ListIterator it = l.listIterator();
		while(it.hasNext()) {
			String s = (String)it.next();
			if(s.equals("xyz")) {
				it.remove();//删除元素xyz
			}
		}
		System.out.println(l);
		//倒序输出
		while(it.hasPrevious()) {
//			String s = (String)it.previous();
			System.out.println(it.previous());
		}
	}
}

LinkedList

特点

  • 底层数据结构是链表。
  • 添加和删除速度快,但查询速度较慢。

方法

基本方法与ArrayList相同,特有方法如下:

方法 意义
offer(E e) 在表尾存入元素
offerFirst(E e) 在表头存入元素
offerLast(E e) 在表尾存入元素
peekFirst() 获取第一个元素,若表为空,则返回null
peekLast() 获取最后一个元素,若表为空,则返回null
pollFirst() 删除第一个元素,若表为空,则返回null
pollLast() 删除最后一个元素,若表为空,则返回null

练习:去除List中的重复元素

package set;

import java.util.*;
/*
 * 去除List中的重复元素
 */
public class RemoveDuplicateElements {
	public static void main(String[] args) {
		LinkedList l = new LinkedList();
		l.offer("123");
		l.offer("456");
		l.offer("XiaoMing");
		l.offerFirst("XiaoMing");
		l.offerLast("LiHua");
		System.out.println(l);//[XiaoMing, 123, 456, XiaoMing, LiHua]
		
		LinkedList l1 = (LinkedList)RDElements(l);
		System.out.println(l1);//[XiaoMing, 123, 456, LiHua]
		
	}
	public static List RDElements(List l) {
		//去除重复元素
		//定义一个临时容器
		LinkedList tempList = new LinkedList();
		Iterator it = l.iterator();
		while(it.hasNext()) {
			Object obj = it.next();
			//contains()实际上在隐式调用equals()
			if(!tempList.contains(obj)) {
				tempList.add(obj);
			}
		}
		return tempList;
	}
}

Map

  • Map 用于保存具有映射关系的数据,因此 Map 集合里保存着两组值,一组值用于保存 Map 里的 Key,另外一组用于保存 Map 里的 Value。
  • Map 中的 key 和 value 都可以是任意引用类型的数据。
  • Map 中的 Key 不允许重复。
  • Key 和 Value 之间存在单向一对一关系,即通过指定的 Key 总能找到唯一的、确定的 Value。

HashMap

特点

  • HashMap 可以使用 null 作为 key 和 value,键值对无序
  • HashMap 通过key值的 hashCode() 和 equals() 方法判断key是否相同。
  • 底层数据结构是哈希表,是线程不同步的。

方法

JavaSE学习笔记——异常处理、集合_第5张图片

方法 意义
put(Object k, Object v) 放入元素到map中
putAll(map m) 在map中放入另一个map
remove(Object k) 移除key值为k的键值对(k, v)
clear() 清空map
containsKey(Object k) 判断map中是否包含 key = k
containsValue(Object v) 判断map中是否包含 value = v
isEmpty() 判断map是否为空
get(Object k) 根据key值获取对应的value值
size() 获取map的长度
Collection< V > values() 获取map集合的value集合
Set< K > keySet() 获取map集合的key集合
Set> entrySet() 获取map集合的键值对(key, value)集合
Map.Entry提供的方法 意义
getKey() 获取key
getValue() 获取value
setValue(V value) 用指定的值替换当前key的value值

注意:
Map集合添加元素时,若两次添加的key值相同,则新value代替旧value,put()方法会返回被覆盖的值。

遍历Map

map集合取出元素的两种方式:
1.keySet()
2.entrySet()

package abc;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class TestHashMap {
	public static void main(String[] args) {
		Map map = new HashMap();
		//添加元素
		map.put(1, "LiHua");
		map.put(2, "XiaoMing");
		map.put(3, "XiaoGang");
		map.put("DaLi", 22);
		map.put("TongTong", 22);
		
		//遍历map集合
		//方法一
		for(Object obj : setkeys) {
			System.out.println(obj + ": " + map.get(obj));
		}
		//方法二
		Set<Map.Entry<Object, Object>> entrys = map.entrySet();
		for(Entry<Object, Object> en : entrys) {
			System.out.println("key: " + en.getKey() + "\tvalus: " + en.getValue());
		}
		//方法三
		Iterator it = entrys.iterator();
		while(it.hasNext()) {
			Map.Entry en = (Map.Entry)it.next();
			System.out.println("key: " + en.getKey() + "\tvalus: " + en.getValue());
		}
	}
	
}

示例

package set;

import java.util.*;

public class HashMapDemo {
	public static void main(String[] args) {
		Map<String, Integer> map = new HashMap<String, Integer>();
		map.put("LiHua", 20);
		map.put("LiMing", 21);
		map.put("XiaoHong", 19);
		map.put("LiHua", 22);//key相同时, 新value覆盖旧value
		System.out.println(map);//{XiaoHong=19, LiHua=22, LiMing=21}
		//获取map中的所有value
		Collection<Integer> coll = map.values();
		//集合转换成数组后, 遍历输出
		Object[] obj = coll.toArray();
		for(Object o : obj) {
			Integer i = (Integer)o;
			System.out.println(i);
		}
		//方式1: keyset()遍历map集合
		Set<String> s = map.keySet();
		Iterator<String> it = s.iterator();
		while(it.hasNext()) {
			//不需要强制转换
			String key = it.next();
			Integer value = map.get(key);
			System.out.println("key: "+key+"\tvalue: "+value);
			/*
			key: XiaoHong	value: 19
			key: LiHua	value: 22
			key: LiMing	value: 21
			*/
		}
		//方式2: entrySet()遍历map集合
		Set<Map.Entry<String, Integer>> set = map.entrySet();
		Iterator<Map.Entry<String, Integer>> iter = set.iterator();
		while(iter.hasNext()) {
			Map.Entry<String, Integer> m = iter.next();
			String key = m.getKey();
			Integer value = m.getValue();
			System.out.println("key: "+key+"\tvalue: "+value);
		}
	}
}

TreeMap

特点

  • TreeMap默认根据 key对象的CompareTo()方法对key值进行排序。
  • TreeMap 实现排序与TreeSet相同。
  • TreeMap底层的数据结构是二叉树,是线程不同步的。

方法

与HashMap相同。

package set;

import java.util.*;

/**
 * 每个学生都有自己的归属地, 保证学生唯一性
 * 
 * 定义map, Student为key, address为value.
 * @author 14251
 *
 */
class MyStudent implements Comparable<MyStudent>{
	private String name;
	private int age;
	MyStudent(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;
	}
	@Override
	public int hashCode() {
		return this.name.hashCode() + this.age*39;
	}
	@Override
	public boolean equals(Object obj) {
		if(obj instanceof MyStudent) {
			MyStudent s = (MyStudent)obj;
			return this.name.equals(s.name) && this.age == s.age;
		}else {
			throw new ClassCastException("Can not cast the Object to Student");
		}
	}
	public int compareTo(MyStudent s) {
		//姓名, 年龄排序
		int num = this.name.compareTo(s.name);
		if(num == 0) {
			Integer i1 = this.age;
			Integer i2 = s.age;
			num = i1.compareTo(i2);
		}
		return num;
	}
	
}

//比较器
class StuComparator implements Comparator<MyStudent>{
	public int compare(MyStudent s1, MyStudent s2) {
		//年龄, 姓名排序
		Integer i1 = s1.getAge();
		Integer i2 = s2.getAge();
		int num = i1.compareTo(i2);
		if(num == 0) {
			num = s1.getName().compareTo(s2.getName());
		}
		return num;
	}
}

public class TreeMapDemo {
	public static void main(String[] args) {
		Map<MyStudent, String> map = new TreeMap<MyStudent, String>(new StuComparator());
		map.put(new MyStudent("C", 18), "c");
		map.put(new MyStudent("D", 23), "d");
		map.put(new MyStudent("A", 20), "a");
		map.put(new MyStudent("B", 21), "b");
		map.put(new MyStudent("A", 20), "a");
		
		//取出
		Set<Map.Entry<MyStudent, String>> entrySet = map.entrySet();
		Iterator<Map.Entry<MyStudent, String>> it = entrySet.iterator();
		while(it.hasNext()) {
			Map.Entry<MyStudent, String> me = it.next();
			MyStudent ms = me.getKey();
			String address = me.getValue();
			System.out.println("name: "+ms.getName()+"\tage: "+ms.getAge()+"\taddress: "+address);
		}
		
//		//取出
//		Set set = map.keySet();
//		Iterator iter = set.iterator();
//		while(iter.hasNext()) {
//			MyStudent ms = iter.next();
//			String address = map.get(ms);
//			System.out.println("name: "+ms.getName()+"\tage: "+ms.getAge()+"\taddress: "+address);
//		}
	}
}

练习

获取一个字符串中每个字符出现的次数,例如"hackfhueinanvaw", 输出:a(3)c(1)…

package set;

import java.util.*;
/**
 * 获取一个字符串中每个字符出现的次数, 
 * 例如"hackfhueinanvaw", 输出: a(3)c(1)...
 * @author 14251
 * 1. 将字符串转换为字符数组
 * 2. 统计字符数组中每个字符出现的次数
 * 3. 定义TreeMap集合(输出字符有序), key: 字符, value: 出现的次数
 * 4. 遍历字符数组, 将每个字符看作是一个key, 去map中查询是否存在, 若get()返回null, 则将该字符与1存入;
 *    若返回value, 则将次数自增1, 再将该字符与自增后的次数存入map, 覆盖原键值对.
 * 5. 将map集合转换为字符串输出.
 */
public class CountString {
	public static void main(String[] args) {
		String str = "h/ackcc+fh-ei=a";
		String res = printResult(countChar(str));
		System.out.println(res);//a(2) c(3) e(1) f(1) h(2) i(1) k(1)
	}
	//存数据
	public static Map<Character, Integer> countChar(String str) {
		char[] ch = str.toCharArray();//字符串转换为字符数组
		Map<Character, Integer> map = new TreeMap<Character, Integer>();
		int count = 0;//计数器
		for(int i=0; i<ch.length; i++) {
			if(!(ch[i]>='a'&&ch[i]<='z' || ch[i]>='A'&&ch[i]<='Z')) {
				continue;//不统计运算符
			}
			if(map.get(ch[i]) != null) {
				count = map.get(ch[i]) + 1;//更新次数
				map.put(ch[i], count);//存入字符和次数
			}else {
				map.put(ch[i], 1);
			}
			/*
			Integer value = map.get(ch[i]);
			if(value!=null) {
				count = value;
			}
			count++;
			map.put(ch[i], count);
			count = 0;
			*/
		}
		return map;
	}
	//打印数据
	public static String printResult(Map<Character, Integer> map) {
		//存放要求的字符打印形式
		StringBuilder sb = new StringBuilder();//临时存放字符, 按照执行形式输出
		Set<Map.Entry<Character, Integer>> set = map.entrySet();
		Iterator<Map.Entry<Character, Integer>> it = set.iterator();
		while(it.hasNext()) {
			Map.Entry<Character, Integer> me = it.next();
			Character ch = me.getKey();
			Integer i = me.getValue();
			sb.append(ch+"("+i+")"+" ");//存入缓冲器
		}
		return sb.toString();//转换为字符串
	}
}

Map嵌套

package set;

import java.util.*;
/**
 * 一个公司有许多个子公司, 每个子公司有许多个部门, 每个部门下又有许多员工, 
 * 假设这个公司为集合map, key为子公司名称, value为子公司的各个部门, 各个部门下又有人员信息.
 * 用Employee描述员工, 之后再遍历集合, 输出map信息
 * 格式如: (总公司名称, (子公司名称, (部门, (姓名, id))))
 * @author 14251
 *
 */
class Employee implements Comparable<Employee>{
	private String name;
	private String id;
	Employee(String name, String id){
		this.name = name;
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	//重写hashCode()
	public int hashCode() {
		return this.name.hashCode()+this.id.hashCode();
	}
	//重写equals()
	public boolean equals(Object obj) {
		if(obj instanceof Employee) {
			Employee e = (Employee)obj;
			return this.name.equals(e.name) && this.id.equals(e.id);
		}else {
			throw new ClassCastException("Can not cast the Object to Student");
		}
	}
	//实现Comparator接口
	public int compareTo(Employee e) {
		int num = this.name.compareTo(e.name);
		if(num == 0) {
			num = this.id.compareTo(e.id);
		}
		return num;
	}
}

public class MultiMap {
	public static void main(String[] args) {
		//总公司集合headOffice
		//<子公司,子公司结构<部门, 人员>>
		Map<String, Map<String, Employee>> headOffice = new HashMap<String, Map<String, Employee>>();
		Map<String, Employee> branchOffice1 = new HashMap<String, Employee>();
		Map<String, Employee> branchOffice2 = new HashMap<String, Employee>();
		Map<String, Employee> branchOffice3 = new HashMap<String, Employee>();
		//子公司1
		branchOffice1.put("技术", new Employee("LiHua", "t101-1"));
		branchOffice1.put("销售", new Employee("LiuGang", "s101-1"));
		branchOffice1.put("服务", new Employee("XiaoHong", "s201-1"));
		//子公司2
		branchOffice2.put("技术", new Employee("LiHua", "t101-2"));
		branchOffice2.put("销售", new Employee("LiuGang", "s101-2"));
		branchOffice2.put("服务", new Employee("XiaoHong", "s201-2"));
		//子公司3
		branchOffice3.put("技术", new Employee("LiHua", "t101-3"));
		branchOffice3.put("销售", new Employee("LiuGang", "s101-3"));
		branchOffice3.put("服务", new Employee("XiaoHong", "s201-3"));
		
		headOffice.put("分公司1", branchOffice1);
		headOffice.put("分公司2", branchOffice2);
		headOffice.put("分公司3", branchOffice3);
		
		Set<Map.Entry<String, Map<String, Employee>>> headSet = headOffice.entrySet();
		String str = new MultiMap().MyIterator(headSet);
		System.out.println(str);
		/*
		 * (分公司2, (技术, (LiHua, t101-2))(服务, (XiaoHong, s201-2))(销售, (LiuGang, s101-2)))
		 * (分公司3, (技术, (LiHua, t101-3))(服务, (XiaoHong, s201-3))(销售, (LiuGang, s101-3)))
		 * (分公司1, (技术, (LiHua, t101-1))(服务, (XiaoHong, s201-1))(销售, (LiuGang, s101-1)))
		 */
	}
	//迭代器
	public String MyIterator(Set<Map.Entry<String, Map<String, Employee>>> set) {
		Iterator<Map.Entry<String, Map<String, Employee>>> it = set.iterator();
		String str = "";
		while(it.hasNext()) {
			Map.Entry<String, Map<String, Employee>> me = it.next();
			String branchCompanyName = me.getKey();//子公司名称
			Map<String, Employee> branchCompany = me.getValue();//部门, 人员信息
			str += MyBuilder(branchCompanyName, MyInnerIterator(branchCompany));
		}
		return str;
	}
	//内层迭代器
	public String MyInnerIterator(Map<String, Employee> map) {
		Set<Map.Entry<String, Employee>> headSet = map.entrySet();
		Iterator<Map.Entry<String, Employee>> it = headSet.iterator();
		String str = "";
		while(it.hasNext()) {
			Map.Entry<String, Employee> me = it.next();
			String departmentName = me.getKey();
			Employee employee = me.getValue();
			//避免后一次迭代将前一次保存的str覆盖,
			//而是将每次循环输出的str加在一起
			str += MyBuilder(departmentName, employee);
		}
		return str;
	}
	//存储区
//	public String MyData(String str, Employee e) {
//		StringBuilder sb = new StringBuilder();
//		String name = e.getName();
//		String id = e.getId();
//		sb.append("("+str+", "+"("+name+", "+id+"))\n");
//		return sb.toString();//(部门, (姓名, id)))
//	}
	//存储区
	public String MyBuilder(String str, Object obj) {
		StringBuilder sb = new StringBuilder();
		if(obj instanceof Employee) {
			Employee e = (Employee)obj;
			String name = e.getName();
			String id = e.getId();
			sb.append("("+str+", "+"("+name+", "+id+")) ");
		}
		if(obj instanceof String) {
			String s = (String)obj;
			sb.append("("+str+", "+s+")\n");
		}
		return sb.toString();//(部门, (姓名, id)))
	}
}

你可能感兴趣的:(java)