【蓝旭】第二周预习博客


一、java异常类

1、引入

例如,下面这个程序:
数组下标越界的错误
指出了数组下标越界的错误,并表面错误在第四行。


经调试后,输出正确且没有异常。


2、异常的概念

▲ Java异常是Java提供的用于处理程序中错误的一种机制。

▲ 所谓错误是指在程序运行的过程中发生的一些异常事件(如:除0溢出,数组下标越界,所要读取的文件不存在)。

▲ 设计良好的程序应该在异常发生时提供处理这些错误的方法,使得程序不会因为异常的发生而阻断或产生不可预见的结果。

▲ Java程序的执行过程中如出现异常事件,可以生成一个异常类对象,该异常对象封装了异常事件的信息并将被提交给Java运行时系统,这个过程称为抛出(throw)异常

▲ 当Java运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获(catch)异常


声明该方法可能抛出的异常;
构造并抛出异常对象。


调用该方法时试图捕获异常;
定义处理异常的代码。


3、异常的分类

Java语言按照错误严重性,从throwale根类衍生出Error和Exception两大派系。


Error:程序在执行过程中所遇到的硬件或操作系统的错误。错误对程序而言是致命的,将导致程序无法运行。常见的错误有内存溢出,jvm虚拟机自身的非正常运行,calss文件没有主方法。程序本生是不能处理错误的,只能依靠外界干预。Error是系统内部的错误,由jvm抛出,交给系统来处理。

Exception:是程序正常运行中,可以预料的意外情况。比如数据库连接中断,空指针,数组下标越界。异常出现可以导致程序非正常终止,也可以预先检测,被捕获处理掉,使程序继续运行。

Runtime Exception:一类特殊的异常,如被0除、数组下标超范围等,其产生比较频繁,处理麻烦,如果显示的声明或捕获将会对程序可读性和运行效率影响很大。因此由系统自动检测并将它们交给缺省的异常处理程序(用户可不必对其处理)。


4、异常的捕获和处理

try {
//可能抛出异常的语句
} catch (SomeException1 e)
{
......
} catch (SomeException2 e)
{
......
} finally {
......
}

▲ try代码段包含可能产生例外的代码。

▲ try代码段后跟有一个或多个catch代码段。

▲ 每个catch代码段声明其能处理的一种特定类型的异常并提供处理的方法。

▲ 当异常发生时,程序会中止当前的流程,根据获取异常的类型去执行相应的catch代码段。

▲ finally段的代码无论是否发生异常都有执行。

(1)try语句

①try{…}语句指定了一段代码,该代码就是一次捕获并处理例外的范围。

②在执行过程中,该段代码可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句要分别对这些异常做相应的处理。

③如果没有例外产生,所有的catch代码段都被略过不执行。

(2)catch语句

①在catch语句块中是对异常进行处理的代码,每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。

②在catch中声明的异常对象(catch (SomeException e))封装了异常事件发生的信息,在catch语句块中可以使用这个对象的一些方法获取这些信息。

③例如:
▲ getMessage()方法,用来得到有关异常事件的信息。
▲ printStackTrace()方法,用来跟踪异常事件发生时执行堆栈的内容。

(3)finally语句

①finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部分以前,能够对程序的状态作统一的管理。

②无论try所指定的程序块中是否抛出例外,finally所指定的代码都要被执行。

③通常在finally语句中可以进行资源的清除工作,如:
▲ 关闭打开的文件
▲ 删除临时文件
▲ …

try {
	in = new FileInoutStream("myfile.txt");
	int b;
	b = in.read();
	while (b != -1) {
		System.out.print((char) b);
		b = in.read();
	}
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	System.out.println(e.getMessage());
} finally {
	try {
		in.close();
	} catch (IOException e) {
		e.printStackTrace();
	}
}
public class Test {
	public static void main(String args[]) {
		Test test = new Test();
		try {
			test.method1();
		} catch (SomeException e) {
			e.printStackTrace();
		}
	}
	public void method1()
			throws SomeException{method2();}
	public void method2()
			throws SomeException{method3();}
	public void method3()
		throws  new SomeException
				("SomeException occur in method3");
	}
}

在一个try语句块中,基类异常的捕获语句不可以写在子类异常捕获语句的上面。
如下面这个程序,会有编译错误:

public class Test {
	public static void main(String args[]) {
		String[][] s = new String[5][];
		try {
			s[1][0] = "hello"; s[1][1] = “你好";
		} catch (NullPointerException e) {
			System.out.println("数组元素没有正确实例化");
		}
		try {
			s[5] = new String[3]; s[5][1] = "hello";
		} catch (Exception e2) {
			System.out.println("数组下标越界了");
		} catch (ArrayIndexOutOfBoundsException e1) {
			System.out.println("有异常发生了");
		}
	}
}
		

5、使用自定义的异常

使用自定义异常一般有如下步骤:

① 通过继承java.lang.Exception类声明自己的异常类。
② 在方法	适当的位置生成自定义异常的实例,并用throw语句抛出。
③在方法的声明部分用throws语句声明该方法可能抛出的异常。

声明并抛出异常:

public class Test {
	public void regist(int num) throws MyException {
		if (num < 0) {
			throw new MyException("人数为负值,不合理"3);
		}
		System.out.println("登记人数" + num);
	}
	public void manager() {
		try {regist(100);}
		catch (MyException e) {
			System.out.println("登记错误,出错类型码=+ e.getId());
			e.printStackTrace();
		}
		System.out.print("操作结束");
	}
	public static void main(String[] args) {
		Test t = new Test();
		t.manager();
	}

注意:
重写方法需要抛出与原方法所抛出异常类型一致异常或不抛出异常。


总结


二、Java常用类

1、Object类

(1)概述

▲ Java可以把任何类型的对象赋值给Object类型的变量。

▲ 如果一个类在声明时没有使用extends关键字为其显示指定父类,则该类默认继承Object类。

▲ 所有数组类型都继承于Object类(包括对象数组和基本数据类型数组)。

(2)常用方法


示例:

UserInfo userInfo=new UserInfo();
//当前对象与行创建的UserInfo对象比较内存地址
boolean  flag=this.equals(userInfo);
System.out.println("equals()返回值:"+flag);  
//调用本类中重写父类的toString()方法
String tsResult=this.toString();
System.out.println("toString()返回值:"+tsResult);
//调用hashCode()方法
int hashCode=this.hashCode();
System.out.println("hashCode()返回值:"+hashCode);
//重写Object类的toString()
 public String  toString(){ return "重写了父类的toString方法"; }

(3)实践

public class Dog {	
	public String dogName;public boolean equals(Object obj){ //重写equals()
		if (obj==null)
			return false;
		if(!(obj instanceof Dog))
			return false;	
		Dog other = (Dog) obj;
        		if (dogName.equals(other.dogName)){
            			 return true;
		else
			return false;
       		 }
	}	
	public static void main(String args[]){
	              Dog dog0 = new Dog();
	              dog0.setDogName("xiaobai");
	              Dog dog1 = new Dog();
	             dog1.setDogName("xiaobai");  
	             System.out.println("dog0.equals(dog1):"+dog0.equals(dog1); 
	}
}

2、String类和StringBuffer类

(1)概述

▲ String类和StringBuffer类主要用于处理字符串,这两个类提供了许多字符串的实用处理方法。

▲ String类是一个不可变类(被final修饰),一个String对象所包含的字符串内容永远不会被改变。

▲ StringBuffer类是可变类,一个StringBuffer对象所包含的字符串内容可以被 添加或修改。

(2)String类构造方法和常用方法


示例:

int index=value.indexOf("A"); //第一次出现指定字符串的下标,如果未出现,则返回-1
System.out.println("第一次出现字母A的下标:"+index);
int length=value.length();//字符串的长度
System.out.println("输入字符串的长度:"+length);
boolean  flag="Hello String".equals(value); //判断两个字符串字面值是否相等
System.out.println("控制台输入的字符串是否与Hello String字面值相等:"+flag);
boolean  tag=value.endsWith(.java”); //判断结尾处是否包含“.java” 
System.out.println("控制台输入的字符串是否以.java结尾:"+tag);
String newValue=value.toUpperCase(); //转换大写字母
System.out.println("控制台输入字符串转换为大写字母值:"+newValue);
String val=value.substring(0, 2); //字符串截取
System.out.println("按照从0下标开始截取长度为2的子字符串:"+val);
String[] str=value.split("-"); //按照给定格式拆分字符串,返回一个String[]数组
System.out.println("将按照-拆分后返回的字符串数组遍历结果:");
for(String data:str){ System.out.println(data); }

注意:
▲ ==”比较的是两个对象的内存地址是否相同,而Object中的equals()方法默认比较的也是两个对象的内存地址是否相同。

▲ 但由于String类重写了Object类的equals()方法,重写的逻辑是比较当前调用对象与被比较对象的字符串字面值,如果相同则返回true,否则返回false。

(3)StringBuffer类常用方法

StringBuffer代表一个字符序列可变的字符串。

StringBuffer提供的append()、insert()、reverse()以及setCharAt()等方法,可以改变该StringBuffer对象的字符序列。


示例:

StringBuffer  stringBuffer=new StringBuffer();
stringBuffer.append("Intelligence"); //追加字符串
System.out.println("当前stringBuffer对象值:"+stringBuffer);
System.out.println("在下标0插入Artificial后的值:"+stringBuffer.insert(0,"Artificial ")); //在指定位置添加字符串
stringBuffer.replace(10, 11, "-"); //将指定位置的内容进行替换	
System.out.println("stringBuffer长度:"+stringBuffer.length());
System.out.println("翻转后的内容:"+stringBuffer.reverse()); //将内容进行反转
String str="Java";
String newStr=str+" Android"; //将"Java"字符串与“ Android”字符串连接后赋值给newStr变量
System.out.println("str的值="+str);
System.out.println("newStr值="+newStr);
System.out.println("str==newString?="+(str==newStr));
StringBuffer sb=new StringBuffer();
sb.append("Cloud");
System.out.println("sb的值="+sb);
StringBuffer sBuffer=sb.append(" Computing");
System.out.println("sBuffer的值="+sBuffer);
System.out.println("sb==sBuffer?="+(sb==sBuffer));

注意:
String是不可变类,如果使用String创建字符串,则会额外生成很多字符串,耗费系统资源。

(4)实践

char[] ch = str.toCharArray();  
Arrays.sort(ch); //对数组排序  
char max = '0'; //记录出现次数最多的元素  
int maxcount = 0; //记录最大出现次数  
int count = 1; //判断当前元素出现次数  
for (int i = 0; i < ch.length - 1; i++) {   
	if (ch[i] == ch[i + 1])
		count++;  
	if (ch[i] != ch[i + 1]) {  
		if (count > maxcount) {  
			maxcount = count;  
            max = ch[i];  
        }  
        count = 1;  
	}  
} 
public static String arrayToString2(int[] arr) {
	//定义一个内容为"["的StringBuffer的缓冲区
	StringBuffer sb = new StringBuffer();
	sb.append("[");
	//进行数组的遍历,以及转换为StringBuffer缓冲区
	for(int x=0;x<arr.length;x++){
		if(x == arr.length-1){
			sb.append(arr[x]);
		}else{
			sb.append(arr[x]).append(",");
		}
	}
	sb.append("]");    
	//StringBuffer转换成String
	return sb.toString();    
}

3、Math类

(1)概述

▲ Java提供“+” 、 “-” 、 “*” 、 “/” 和 “%” 等基本算术符运算符。

▲ 但对于较为复杂的运算,如三角函数、指数函数和绝对值函数等运算,基本运算符无法完成相关的操作。

▲ Java提供了工具Math类来完成这些复杂的运算。

▲ Math类的方法都是静态方法

(2)示例

System.out.println("27的算数立方根的值="+Math.cbrt(27));
System.out.println("4的平方根的值="+Math.sqrt(4));
System.out.println("3的2次方的值="+Math.pow(3, 2));
System.out.println("-4.5的绝对值="+Math.abs(-4.5));
System.out.println("8和10两个数的最大值="+Math.max(10, 8));
//返回一个随机数,该值的范围在0.0~1.0之间
System.out.println("产生的随机数值="+Math.random());
System.out.println("5.5四舍五入后的值="+Math.round(5.5));
System.out.println("弧度为π/6的正弦值="+Math.sin(Math.PI/6));

(3)实践

Scanner scan = new Scanner(System.in);
int number = (int) (Math.random() * 100 + 1);
while(true) {
	System.out.println("请输入一个正整数:");
	int guessNumber = scan.nextInt();
	if (guessNumber > number) {
		System.out.println("猜大了。");
	    continue;
	} else if (guessNumber < number) {
		System.out.println("猜小了。");
	    continue;
	} else {
		System.out.println("恭喜,猜对了。");
	    break;
	}
}

4、Date类

(1)概述

▲ Java提供了java.util.Date类处理日期、时间,Date对象既包含日期,也包含时间。

▲ Date类提供了两个构造器。

(2)构造方法

注意:
▲ Date类的很多方法已经不推荐使用了。例如,对时间进行加减运算,获取指定Date对象的年、月、日的所有方法都已被弃用。

▲ 如果需要对日期进行这些运算,则应该使用Calendar工具类。

示例:

//使用无参构造方法创建Date对象
Date date=new Date();
System.out.println("当前系统时间:"+date);
Date newDate=new Date(1000*60*60*24*20);
System.out.println("1970年1月1日的20天后的时间="+newDate);

5、Calendar类

(1)概述

▲ 由于Date类在设计上的一些问题,所以Java提供了Calendar类来更好地处理日期和时间。

▲ Calendar类是一个抽象类,所以不能实例化Calendar对象。但是Calendar类提供过了静态的方法getInstance(),以获得Calendar对象。

▲ Calendar与Date类都是表示日期的工具类,两者可以直接相互转换。

(2)构造方法

通过getInstance()方法创建Calendar的子类对象
Calendar calendar=Calendar.getInstance();

从Calendar中获取Date对象
Date date=calendar.getTime();

通过Date对象获得对应的Calendar对象
calendar.setTime(new Date());

示例:

Calendar  calendar=Calendar.getInstance();
//创建一个距离1970年1月1日2天后的日期对象
Date date=new Date(1000*60*60*24*2);
System.out.println(date);
calendar.setTime(date); //将date对象赋给Calendar对象
System.out.println("年:"+calendar.get(Calendar.YEAR)+"年"); //获取年份	 
System.out.println("月:"+calendar.get(Calendar.MONTH)+1+"月"); //获取月份
System.out.println("日:"+calendar.get(Calendar.DATE)+"日"); //获取日期	
System.out.println("星期:"+(calendar.get(Calendar.DAY_OF_WEEK)-1)); //获取星期
System.out.println("本年的第:"+calendar.get(Calendar.DAY_OF_YEAR)+"天"); //这一天是一年中的第几天

6、SimpleDateFormat类

(1)概述

▲ SimpleDateFormat是一个日期时间格式化类,该类位于java.text包中。

▲ 该类可以灵活地格式化Date对象,也可以用于解析各种格式的日期字符串。

▲ 使用String类型的SimpleDateFormat类的构造器创建对象时,需要传入一个模板字符串。

(2)使用方法


示例:

public class SimpleDateFormatUse {
	private static final String PARRENT1 = "yyyy-MM-dd HH:mm:ss";
	private static final String PARRENT2 = "yyyy年MM月dd日 HH时mm分ss秒";
	public static void parse(String strDate) {
	//创建SimpleDateFormat对象。y代表年、M代表月、d代表日,HH代表24小时制的时、m代表分、s代表秒
	SimpleDateFormat sdf = new SimpleDateFormat(PARRENT1);
	SimpleDateFormat simpleDateFormat = new SimpleDateFormat(PARRENT2);
	try {
		//将字符串日期转换成Date对象
		Date date = sdf.parse(strDate);
		//将date对象重新转换成“yyyy年MM月dd日 HH时mm分ss秒”格式的日期字符串
		String str = simpleDateFormat.format(date);
		System.out.println(strDate + ":解析成的Date=" + date);
		System.out.println("date对象按照"+PARRENT2+"格式转换后的字符串日期:");
		System.out.println(str);
	} catch (ParseException e) {e.printStackTrace();}
}

(3)实践

//获得字符串时间如“2018-05-12”为当前年的第几周
public static int getWeekOfYear(String date){
	try {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		Calendar cal = Calendar.getInstance();
		//设置每周的第一天为星期一
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.setMinimalDaysInFirstWeek(1);  //设置每周最少为1天
		cal.setTime(df.parse(date));
		return cal.get(Calendar.WEEK_OF_YEAR);
	} catch (Exception e) {
		e.printStackTrace();
	}
	return 0;
}

总结

三、容器

1、概述

▲ 容器可以管理对象的生命周期、对象与对象之间的依赖关系。

▲ 直白点说容器就是一段Java程序,能够帮助你管理对象间的关系,而不需要你自行编写程序处理。
维基百科定义:
在计算机科学中,容器是指实例为其他类的对象的集合的类、数据结构、[1][2]或者抽象数据类型。换言之,它们以一种遵循特定访问规则的系统的方法来存储对象。容器的大小取决于其包含的对象(或元素)的数目。
潜在的不同容器类型的实现可能在空间和时间复杂度上有所差别,这使得在给定应用场景中选择合适的某种实现具有灵活性。

2、分类

Java内部的容器类主要分为两类:Collection(集合)与Map(映射)

▲ Collection

Set

HashSet
▲ 基于哈希表实现,底层使用HashMap来保存所有元素。
▲ 不能保证迭代顺序。
▲ 允许使用null元素。

package 常用数据结构;

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

/**
 * @author pony
 * @date 2020/4/28
 */
public class HashSetTest {
    public static void main(String[] args) {
        HashSet<Integer> hs = new HashSet<>();
        for(int i=0;i<5;++i)
            hs.add(i);
        hs.add(1);  //无效的语句,因为集合中已经有1了。
        hs.add(null); //可以容纳null元素
        /**
         * 测试两种遍历
         */
        HashSet<Integer> hs1 = new HashSet<>();
        for(int i=0;i<100000;++i)
            hs1.add(i);
        long start = System.nanoTime();
        Iterator<Integer> iterator = hs1.iterator();
        while (iterator.hasNext())
            iterator.next();
        long end = System.nanoTime();
        System.out.println("迭代器遍历:"+(end-start)+"ms");
        start = System.nanoTime();
        for(Integer item:hs1)
            ;
        end = System.nanoTime();
        System.out.println("for-each遍历:"+(end-start)+"ms");
    }
}

LinkedHashSet
▲ LinkedHashSet底层使用LinkedHashMap来保存所有元素,它继承于HashSet。
▲ 内部使用双向链表维护插入顺序。

代码和上面类似。把HashSet改成LinkedHashSet即可

TreeSet
▲ 基于(TreeMap)红黑树实现。
▲ TreeSet非同步,线程不安全。
▲ TreeSet中的元素支持2种排序方式:自然排序 或者 根据创建TreeSet 时提供的Comparator 进行排序。

package 常用数据结构;

import java.util.TreeSet;

/**
 * @author pony
 * @date 2020/4/28
 */
public class TreeSetTest {
    public static void main(String[] args) {
        TreeSet<Integer> ts = new TreeSet<>();
        for(int i=0;i<10;++i)
            ts.add(i);
        ts.add(100);
        ts.add(20);
        ts.add(45);
        for(Integer item:ts)
            System.out.println(item);
//        ts.add(null); //错误,不支持添加null元素
        ts.add(1); //重复
    }
}

List

ArrayList
▲ 实现 List 接口、底层使用数组保存所有元素。
▲ 相当于动态数组,支持动态扩容。
▲ 不同步。

package 常用数据结构;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * @author pony
 * @date 2020/4/28
 */
public class ArrayListTest {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        for(int i=0;i<5;++i){
            arrayList.add(i);   //这里会自动装箱
        }
        arrayList.add(0); //允许有相同的元素
        arrayList.remove(2);
        arrayList.add(3,9);
        //遍历测试
        ArrayList<Integer> arr1 = new ArrayList<>();
        for(int i=0;i<100000;++i){
            arr1.add(i);
        }
        traverseByIterator(arr1);
        traverseByIndex(arr1);
        traverseByFor(arr1);
    }

    private static void traverseByFor(ArrayList<Integer> arr1) {
        long start = System.nanoTime();
        for(Integer i:arr1)
            ;
        long end = System.nanoTime();
        System.out.println("for遍历:"+(end-start)+"ms");
    }

    private static void traverseByIndex(ArrayList<Integer> arr1) {
        long start = System.nanoTime();
        for(int i=0;i<arr1.size();++i){
            arr1.get(i);
        }
        long end = System.nanoTime();
        System.out.println("随机索引遍历:"+(end-start)+"ms");
    }

    private static void traverseByIterator(ArrayList<Integer> arr1) {
        long start = System.nanoTime();
        Iterator<Integer> iterator = arr1.iterator();
        while (iterator.hasNext())
            iterator.next();
        long end = System.nanoTime();
        System.out.println("迭代器遍历:"+(end-start)+"ms");
    }
}

vector
▲ Vector 可以实现可增长的对象数组。
▲ Vector 实现 List 接口,继承 AbstractList 类,同时还实现RandmoAccess 接口,Cloneable 接口。
▲ Vector 是线程安全的。

LinkedList
▲ LinkedList 是基于链表实现的(通过名字也能区分开来)。
▲ 所以它的插入和删除操作比 ArrayList 更加高效。但也是由于其为基于链表的,所以随机访问的效率要比 ArrayList 差。

package 常用数据结构;

import java.util.Iterator;
import java.util.LinkedList;

/**
 * @author pony
 * @date 2020/4/28
 */
public class LinkedListTest {
    public static void main(String[] args) {
        LinkedList<Integer> linked = new LinkedList<>();
        for(int i=0;i<10;++i){
            linked.add(i);
        }
        System.out.println(linked.size());
        linked.addFirst(10);
        linked.add(3,20);
        linked.remove(3);
        LinkedList<Integer> list = new LinkedList<>();
        for(int i=0;i<100000;++i)
            list.add(i);
        traverseByIterator(list);
        traverseByIndex(list);
        traverseByFor(list);
    }

    private static void traverseByFor(LinkedList<Integer> list) {
        long start = System.nanoTime();
        for(Integer i:list)
            ;
        long end = System.nanoTime();
        System.out.println("for-each遍历:"+(end-start)+"ms");
    }

    private static void traverseByIndex(LinkedList<Integer> list) {
        long start = System.nanoTime();
        for(int i=0;i<list.size();++i)
            list.get(i);
        long end = System.nanoTime();
        System.out.println("随机索引遍历:"+(end-start)+"ms");
    }

    private static void traverseByIterator(LinkedList<Integer> list) {
        long start = System.nanoTime();
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext())
            iterator.next();
        long end = System.nanoTime();
        System.out.println("迭代器遍历:"+(end-start)+"ms");
    }
}

Queue

LinkedList
可以用于实现双向队列。

PriorityQueue

▲ 通过二叉小顶堆实现,可以用一棵完全二叉树表示。
▲ 可以用于实现优先队列。优先队列的作用是能保证每次取出的元素都是队列中权值最小的(Java的优先队列每次取最小元素,C++的优先队列每次取最大元素)。

▲ Map(用于映射(键值对)问题处理)

HashMap

▲ HashMap根据键的HashCode来实现,访问速度较快,遍历顺序并不确定。
▲ HashMap最多只允许一条记录的键为null,允许多条记录的值为null。
▲ HashMap线程不安全,也就是说任意时刻可以有多个线程同时写HashMap,所以可能会导致数据的不一致。
▲ 如何确保线程安全?可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap。

package 常用数据结构;

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

/**
 * @author pony
 * @date 2020/4/28
 */
public class HashMapTest {
    public static void main(String[] args) {
        HashMap<Integer, String> ht = new HashMap<>();
        ht.put(1,null);
        ht.put(null,"1");
        ht.put(null,null);
        ht.put(1,"111");
        ht.put(2,"222");
        ht.put(3,"3333");
        ht.containsValue("111");
        ht.containsKey(0);
        Iterator<Integer> iterator2 = ht.keySet().iterator();
        while (iterator2.hasNext()){
            Integer key = iterator2.next();
            System.out.println(key+":"+ht.get(key));
        }
        /**
         * 三种遍历方式
         */
        ht.clear();
        for(int i=0;i<100000;++i)
            ht.put(i,"aaaa");
        //第一种:Entry迭代器遍历
        long start = System.nanoTime();
        Iterator<Map.Entry<Integer, String>> iterator = ht.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer, String> next = iterator.next();
            next.getKey();
            next.getValue();
        }
        long end = System.nanoTime();
        System.out.println("Entry迭代器遍历:"+(end-start));
        //第二种:keySet迭代器遍历
        start=System.nanoTime();
        Iterator<Integer> iterator1 = ht.keySet().iterator();
        while (iterator1.hasNext()){
            Integer key = iterator1.next();
            String value = ht.get(key);
        }
        end = System.nanoTime();
        System.out.println("keySet迭代器遍历:"+(end-start));
    }
}

HashTable

▲ HashTable是遗留类,多数功能与HashMap类似,继承自Dictionary类。
▲ HashTable是线程安全的。也就是说任意时刻只有一个线程能够写HashTable。
▲ HashTable的并发性不如ConcurrentHashMap,因为ConcurrentHashMap引入了分段锁。

package 常用数据结构;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

/**
 * @author pony
 * @date 2020/4/28
 */
public class HashtableTest {
    public static void main(String[] args) {
        Hashtable<Integer, String> ht = new Hashtable<>();
//        ht.put(1,null); 报错
//        ht.put(null,"1"); 报错
//        ht.put(null,null); 报错
        ht.put(1,"111");
        ht.put(2,"222");
        ht.put(3,"3333");
        ht.contains("111");
        ht.containsValue("111");
        ht.containsKey(0);
        /**
         * 三种遍历方式
         */
        ht.clear();
        for(int i=0;i<100000;++i)
            ht.put(i,"aaaa");
        //第一种:Entry迭代器遍历
        long start = System.nanoTime();
        Iterator<Map.Entry<Integer, String>> iterator = ht.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer, String> next = iterator.next();
            next.getKey();
            next.getValue();
        }
        long end = System.nanoTime();
        System.out.println("Entry迭代器遍历:"+(end-start));
        //第二种:keySet迭代器遍历
        start=System.nanoTime();
        Iterator<Integer> iterator1 = ht.keySet().iterator();
        while (iterator1.hasNext()){
            Integer key = iterator1.next();
            String value = ht.get(key);
        }
        end = System.nanoTime();
        System.out.println("keySet迭代器遍历:"+(end-start));
    }
}

LinkedHashMap

▲ 基于哈希表和链表实现,借助双向链表确保迭代顺序是插入的顺序。

TreeMap

▲ 基于红黑树实现
▲ 默认按照键值得升序进行排序。
▲ 在使用TreeMap时,key必须实现Comparable接口或者在构造TreeMap传入自定义的Comparator,否则会在运行时抛出java.lang.ClassCastException类型的异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值