Map与Debug追踪

 

  • Map

  • Debug追踪

HashMap存储自定义类型键值

当给HashMap中存储自定义对象时,如果自定义对象作为key存在,这时要保证对象的唯一性,必须重写对象的hashCode和equals方法

如果要保证map中存储元素的顺序。主要体现在key值,可以使用java.util.LinkedHashMap集合来存放

LinkedHashMap

咱们知道HashMap保证成对元素的唯一,并且查询速度相对较快,但是成对元素存放进去无法保证顺序,既要保证有序,又要保证速度快可以使用LinkedHashMap

示例代码:

HashTable

java.util.Hashtable<K,V> implements Map<K,V>接口

  • Hashtable:底层是一个哈希表,是一个线程安全的集合,是单线程的集合,速度慢

  • HashMap: 底层也是一个哈希表,是一个线程不安全的集合,是多线程的集合,速度快

  • HashMap集合:可以存储null key值,null value值

  • Hashtable集合:不可以存储null值,null键

  • Hashtable 和 Vector集合一样,在JDK1.2版本之后被更先进的集合(HashMap,ArrayList)取代了

  • Hashtable有一个子类Properties依然活跃在历史的舞台上

  • Properties集合是一个唯一和IO流相结合的集合

练习:每位学生(姓名,年龄) 都有自己的家庭地址,学生作为键key值,家庭地址作为value值

注意:同名同年龄的学生为同一学生

示例代码:

public class Student {

	private String name;
	private Integer age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public Student() {
		super();
	}

	public Student(String name, Integer age) {
		super();
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((age == null) ? 0 : age.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (age == null) {
			if (other.age != null)
				return false;
		} else if (!age.equals(other.age))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

}
/*
 * 	
 * HashMap存储自定义的类型
 * Map集合要保证key值的唯一性
 * 	   作为key的元素,必须重写hashCode和equals方法
 */
public class Demo01HaspMap {

	public static void main(String[] args) {
		show02();

	}

	/*
	 * key:String类型 String类重写hashCode和equals方法,保证key唯一 value: Student类型
	 * value值允许重复的(同名同年龄为同一个人)
	 */
	public static void show02() {
		// 构建一个map集合
		HashMap<String, Student> map = new HashMap<>();
		map.put("洛阳市", new Student("范秀媛", 18));
		map.put("平顶山市", new Student("范秀媛", 18));
		map.put("南阳市", new Student("范秀媛", 18));
		map.put("郑州市", new Student("范秀媛", 18));
		// 查看下存储的元素情况
		// 使用keyset方法
		Set<String> set = map.keySet();
		// 使用迭代器进行遍历
		Iterator<String> iterator = set.iterator();
		while (iterator.hasNext()) {
			String key = iterator.next();
			Student student = map.get(key);
			System.out.println(key + "---->" + student);
		}
		/*
		 * 平顶山市---->Student [name=范秀媛, age=18] 洛阳市---->Student [name=范秀媛, age=18]
		 * 南阳市---->Student [name=范秀媛, age=18] 郑州市---->Student [name=范秀媛, age=18]
		 */
	}

	/*
	 * key:Student类型 不允许重复(同名同年龄的人为同一个人) value:String类型 Student [name=小丽,
	 * age=20]---->八大街 Student [name=小孙, age=20]---->六大街 Student [name=小王,
	 * age=22]---->八大街
	 */
	public static void show01() {
		// 构建一个HashMap集合
		HashMap<Student, String> map = new HashMap<>();
		map.put(new Student("小孙", 20), "六大街");
		map.put(new Student("小孙", 20), "六大街");
		map.put(new Student("小王", 22), "八大街");
		map.put(new Student("小丽", 20), "八大街");

		// 展示map中存储的元素
		// 使用Entry来进行遍历
		Set<Entry<Student, String>> set = map.entrySet();
		// 增强for循环
		for (Entry<Student, String> entry : set) {
			Student key = entry.getKey();
			String value = entry.getValue();
			System.out.println(key + "---->" + value);
		}

	}

}

 

LinkedHashMap

咱们知道HashMap保证成对元素的唯一,并且查询速度相对较快,但是成对元素存放进去无法保证顺序,既要保证有序,又要保证速度快可以使用LinkedHashMap

示例代码:

/*
 * java.util.LinkedHashMap<K,V> extends HashMap<K,V>
 * 数据结构采用的是哈希表+链表结构(记录元素的顺序)实现,具有可预知的迭代顺序
 * 此实现不是同步的
 */
public class Demo01LinkedHashMap {

	public static void main(String[] args) {
		show02();

	}

	// 使用LinkedHashMap
	public static void show02() {
		// 构建一个LinkedHashMap集合对象
		LinkedHashMap<Integer, String> linkedHashMap = new LinkedHashMap<>();
		linkedHashMap.put(65, "A");
		linkedHashMap.put(97, "a");
		linkedHashMap.put(48, "0");
		linkedHashMap.put(57, "9");
		linkedHashMap.put(65, "B");
		// linkedHashMap key不允许重复 有序的
		System.out.println(linkedHashMap);// {65=B, 97=a, 48=0, 57=9}

	}

	public static void show01() {
		HashMap<Integer, String> hashMap = new HashMap<>();
		hashMap.put(65, "A");
		hashMap.put(97, "a");
		hashMap.put(48, "0");
		hashMap.put(57, "9");
		hashMap.put(65, "B");
		// key 不允许重复 无序
		System.out.println(hashMap);// {48=0, 65=A, 97=a, 57=9}/ {48=0, 65=B, 97=a, 57=9}
	}

}
/*
 * java.util.Hashtable<K,V> implements Map<K,V>接口
 * 
 * Hashtable:底层是一个哈希表,是一个线程安全的集合,是单线程的集合,速度慢
 * HashMap: 底层也是一个哈希表,是一个线程不安全的集合,是多线程的集合,速度快
 * 
 * HashMap集合:可以存储null key值,null value值
 * Hashtable集合:不可以存储null值,null键
 * 
 * Hashtable 和 Vector集合一样,在JDK1.2版本之后被更先进的集合(HashMap,ArrayList)取代了
 * Hashtable有一个子类Properties依然活跃在历史的舞台上
 * Properties集合是一个唯一和IO流相结合的集合
 */
public class Demo01Hashtable {

	public static void main(String[] args) {
		// 构建一个HashMap集合
		HashMap<String, String> hashMap = new HashMap<>();
		hashMap.put(null, "abc");
		hashMap.put("abc", null);
		hashMap.put(null, null);

		System.out.println(hashMap);// {null=null, abc=null}
		// 构建一个Hashtable集合
		Hashtable<String, String> hashtable = new Hashtable<>();
		hashtable.put(null, "abc");// NullPointerException
		hashtable.put("abc", null);// NullPointerException
		hashtable.put(null, null);// NullPointerException
		System.out.println(hashtable);

	}

}

 

练习:计算一个字符串中每个字符出现的次数

示例代码:

public static void main(String[] args) {
		// 使用Scanner类获取用户输入的字符串
		Scanner scanner = new Scanner(System.in);
		System.out.println("请输入一个字符串:");
		String input = scanner.next();
		// 使用hashMap集合 存储每个字符出现的次数  字符 --key值    次数---value值
		HashMap<Character,Integer> map = new HashMap<>();
		// 遍历字符串
		for (char c : input.toCharArray()) {
			// c代表的是获取的是每一个字符  containsKey(c)
			if (map.containsKey(c)) {
				// key存在
				map.put(c, map.get(c)+1);
			} else {
				map.put(c, 1);
			}
		}
		// 输出map
		System.out.println(map);
	}

Debug追踪

在Eclipse中断点调试功能,查看程序的运行过程

Debug调试程序:

  • 可以让代码逐行执行,查看代码的执行过程,调试程序中出现的bug

  • 使用方式:

  • 在行号的左边,鼠标左键双击,添加断点(添加到方法的首行,哪里有bug添加到哪里)

  • 右键,选择Debug as --->Run Application 启动debug程序

  • 执行程序:

  • F8: 当前的程序执行到下一个断点处,如果没有下一个断点,那么程序就结束了

  • Terminate:打断整个进程

  • Step into(F5):进入到当前的方法

  • Step Return(F7):退出当前执行的方法

  • Step Over(F6):运行下一行代码,不进方法,但是有断点必须进来

/*
 * Debug调试程序:
 * 		可以让代码逐行执行,查看代码的执行过程,调试程序中出现的bug
 * 使用方式:
 *     在行号的左边,鼠标左键双击,添加断点(添加到方法的首行,哪里有bug添加到哪里)
 *     右键,选择Debug as --->Run Application 启动debug程序
 * 		
 * 执行程序:
 * 		F8: 当前的程序执行到下一个断点处,如果没有下一个断点,那么程序就结束了
 *      Terminate:打断整个进程
 *      Step into(F5):进入到当前的方法
 *      Step Return(F7):退出当前执行的方法
 *      Step Over(F6):运行下一行代码,不进方法,但是有断点必须进来
 */

public class Demo01Debug {

	public static void main(String[] args) {
		int a = 10;
		System.out.println(a);
		for (int i = 0; i < 5; i++) {
			System.out.println(i);
		}
		print();
	}

	public static void print() {
		System.out.println("hello debug!");
		System.out.println("hello debug!");
		System.out.println("hello debug!");
		System.out.println("hello debug!");
		System.out.println("hello debug!");
		System.out.println("hello debug!");
	}

}

作业1 二. {aaa,bbb,ccc},{bbb,ddd},{eee,fff},{ggg},{ddd,hhh}
运算的结果:{aaa,bbb,ccc,ddd,hhh},{eee,fff},{ggg}

   

public static void duplicateRemoval() {
		// 1. 先定义一个初始集合 {aaa,bbb,ccc}
		Set<String> set = new HashSet<>();
		set.add("aaa");
		set.add("bbb");
		set.add("ccc");
		// 2.再依次把后面的集合定义出来
		Set<String> set2 = new HashSet<>();
		set2.add("bbb");
		set2.add("ddd");
		Set<String> set3 = new HashSet<>();
		set3.add("eee");
		set3.add("fff");
		Set<String> set4 = new HashSet<>();
		set4.add("ggg");
		Set<String> set5 = new HashSet<>();
		set5.add("ddd");
		set5.add("hhh");
		// 再定义一个大的容器用来存储后面4个容器
		ArrayList<Set<String>> list = new ArrayList<>();
		list.add(set2);
		list.add(set3);
		list.add(set4);
		list.add(set5);
		// 下面开始遍历list
		for (int i = 0; i < list.size(); i++) {
			// 合并同类项
			Set<String> s = list.get(i);
			// 添加开关
			boolean flag = false;
			for (String str : s) {
				if (set.contains(str)) {
					flag = true;
					set.addAll(s);
					break;
				}
			}
			// 如果有相同的元素。就删除掉那个相同的set集合
			if (flag) {
				list.remove(s);
			}
		}
		System.out.println(set);
		System.out.println(list);

	}
  1. 看牌,通过Map集合查询纸牌与数字的对应的关系,由数字转成纸牌字符串再进行展示。

    二.  {aaa,bbb,ccc},{bbb,ddd},{eee,fff},{ggg},{ddd,hhh}
        运算的结果:{aaa,bbb,ccc,ddd,hhh},{eee,fff},{ggg}
    ​
    三.  已知双色球中的红球数字是1到33的任意值,每次从1到33中随机抽出一个数值,循环10000次,请问循环完毕后,每个数值出现的次数,编写一个程序使用Map集合完成以上要求。
    ​
    四.  使用Java语言完成一个简单的双色球摇奖功能
         双色球规则:
            1. 从1-33号球中选取6个红球,且红球数字最多重复不超过3个
            2. 从1-16号球中选取一个篮球
            3. 由红球和蓝球共同组成一个双色球号码,且红球在左边(按照升序排列),篮球在右边。
        
    五. 短信群发项目:
        编写一个项目,
           1. 以下手机号码段(每隔一个号添加一次),添加到Map集合当中
           2. 从控制台输入要发送信息的短信号码,如果要发送多个,请用英文逗号隔开,输入短信内容
           3. 编写一个短信发送类,号码发送前,先判断号码是否为空,再判断是否为红名单用户(手机号码在集合中),如果为红名           单,输出红名单数据,并计算红名单校验耗费的时间,如果条件都满足,发送短信,短信发送成功的概率为98%, 最后           展示发送成功的短信号码和内容           
              备注:红名单和普通名单可以同时提交发送,但是红名单的不能发送不会影响到普通名单号码的正常发送
              展示的结果:是红名单输出红名单数据和耗费的时间
                         不是红名单输出普通用户的号码和短信的内容。      
        手机号码段:
            头三位     中间四位        末尾四位
             136        0371          0000-9999 
                        0766
                        7335
                        7362
                        6385
                        0769
                        7494
                        3381
                        7496
                        7370
        
             137        3383
                        3319
                        0088
                        8361
                        3315
                        8168
                        8151
                        0386
              181       3788
                        3789
                        3782
                        3787
                        0349
                        3567
                        2234
                        0382
           
              180       3951
                        0169
                        3991
                        3955
                        3928
                        3788
                        0387
                        3997
                        3923
             
               150      0381
                        3719
                        0371
                        3816
                        0389
                        3681
                        0389
                        9326
                        3837
                        3802

 

public class SendMessage {
	// 先定义一个初始化红名单的容器
	public static Map<String, HashMap<String,Set<String>>> redPhonesMap = new HashMap<>();
	
	// 初始化电话号码
	public static void init() {
		String[] headPhone = {"136","137","181","180","150"};
		String[] phone_136 = {"0371", "0766", "7335", "7362", "6385", "0769", "7494", "3381", "7496", "7370"};
        String[] phone_137 = {"3383", "3319", "0088", "8361", "3315", "8168", "8151", "0386"};
        String[] phone_181 = {"3788", "3789", "3782", "3787", "0349", "3567", "2234", "0382"};
        String[] phone_180 = {"3951", "0169", "3991", "3955", "3928", "3788", "0387", "3997", "3923"};
        String[] phone_150 = {"0381", "3719", "0371", "3816", "0389", "3681", "0384", "9326", "3837", "3802"};
		
        //迭代遍历
        for (String head : headPhone) {
        	// 定义一个临时变量
        	String[] temp = {};
        	if (head.equals("136")) {
				temp = phone_136;
			} else if (head.equals("137")) {
				temp = phone_137;
			} else if (head.equals("181")) {
				temp = phone_181;
			} else if (head.equals("180")) {
				temp = phone_180;
			} else if (head.equals("150")) {
				temp = phone_150;
			}
        	// 定义一个方法 用来存储中间四位和末四位手机号码
        	createRedNumber(head,temp);
		}
	}
	
	// 添加真正的红名单号码
	private static void createRedNumber(String head, String[] temp) {
		// 1. 先构建HashMap集合  中间四位和末四位
		HashMap<String, Set<String>> hashMap = new HashMap<>();
		// 2. 遍历temp中间四位的手机号码
		for (String middlePhone : temp) { // 0371  0000--9999   0766  0000--9999
			// 3.构建一个Set集合 用来存储末四位的手机号码
			Set<String> set = new HashSet<>();
			// 0000-9999  每隔一个号添加一次 0000 0002 0004
			//String value = "";
			for (int i = 0; i <= 9999; i+=2) {
				String tailPhone = String.format("%04d", i);// 0000  
				set.add(tailPhone);
			}
			// 每一次迭代中间一个四位号码,就存储一次            一个中间四位号码对应所有的末四位号码  0371  0000--9999 / 7335 0000--9999
			hashMap.put(middlePhone, set);
		}
		redPhonesMap.put(head, hashMap);
		/*   头三位             中间四位                    末四位
		 *   136      0371	    0000-9999
		 *            0766      0000-9999
		 *            7335      0000-9999
		 *           ...
		 *           ...
		 * 
		 */
	}
	
	// 校验红名单的方法 validateRedPhone     redPhonesMap
	// 是红名单就返回true  不是红名单就返回false
	private static boolean validateRedPhone(String phoneNumber) {
		// 1. 先把phoneNumber肢解为头三为 中间四位  末四位
		// substring(int beginIndex,int endIndex) [beginIndex,endIndex-1]
		 String head =  phoneNumber.substring(0,3);// 0 1 2
		 String middle = phoneNumber.substring(3,7);// 3 4 5 6
		 String tail = phoneNumber.substring(7);
		 // 开始校验
		 /*
		  * 	map 集合中有没有一个方法可以判断是否包含某一个key值
		  *      containsKey()
		  */
		 if (redPhonesMap.containsKey(head)) {
			 // 表明头三位满足条件
			 // 取出中间四位和末四位的号码
			 HashMap<String,Set<String>> hashMap = redPhonesMap.get(head);
			 if (hashMap.containsKey(middle)) {
				// 表明中间四位满足,判断末四位号码
				 Set<String> set = hashMap.get(middle);
				 // 是true就返回true,是false就返回false
				 return set.contains(tail);	
			 } else {
				// 说明中间四位不满足 ,该手机号肯定不是红名单
				 return false;
			 }
		} else {
			// 说明头三位就不满足 ,该手机号肯定不是红名单
			return false;
		}
	}
	
	// 校验手机号
	public static int validatePhone(String phoneNumber) {
		/*
		 * 0: 代表可以发送   正常状态	
		 * 1: 输入的手机号码不合法 不是一个正常的手机号码    手机号码长度不满足11位 
		 * 2: 输入的手机号码为红名单
		 * 
		 * String regex = "";
		 * Pattern 用于创建一个正则表达式,构造方法是私有的
		 *   static  compile(regex)---> Pattern.compile(regex)--->正则表达式的对象
		 * Matcher它的构造方法是默认级别的,不能被继承
		 *   static matcher(CharSequence input)--->Pattern.matcher(phoneNumber) --->得到匹配对象
		 *   boolean  matches()  true-->满足正则   false--->不满足
		 * 	
		 */
		if (phoneNumber == null || phoneNumber.length() != 11 ) {
			return 1;
		} else {
			// 校验是否为红名单
			long begin = System.currentTimeMillis();
			boolean result = validateRedPhone(phoneNumber);
			long end = System.currentTimeMillis();
			System.out.println("红名单校验的时间为:" + (end - begin) + "ms");
			// 根据 result的值
			if (result) {
				//表明是红名单
				return 2;
			} else {
				//都满足条件
				return 0;
			}
		}
	}
	
	// 信息发送
	public static void sendMessage(String content,String phoneNumber) {
		// 概率 98%
		Random random = new Random();
		if ((random.nextInt(100)+1) <= 98) { // [1,100]
			System.out.println("向手机号码:" + phoneNumber + ",短信的内容为:" + content);
		} else {
			System.out.println("向手机号码:" + phoneNumber + "发送的短信失败,请重新发送!");
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值