Java基础(五)异常、集合、泛型

异常

Java程序运行过程中所发生的异常事件可分为两类:

§ Error:   JVM 系统内部错误、资源耗尽等严重情况
§ Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,例如:
空指针访问
试图读取不存在的文件
网络连接中断
 

数组越界异常Exception

空指针异常

除数

StackOverFlower:栈溢出  OutOfMemoryError:内存溢出

Java异常类层次

§ RuntimeException
错误的类型转换
数组下标越界
空指针访问
§ IOExeption
从一个不存在的文件中读取数据
越过文件结尾继续读取 EOFException
连接一个不存在的 URL

 Java提供的是异常处理的抓抛模型

 •getMessage( ) 方法,用来得到有关异常事件的信息

printStackTrace( )用来跟踪异常事件发生时执行堆栈的内容。

§程序员通常只能处理Exception,而对Error无能为力。

异常处理是通过try-catch-finally语句实现的。

try catch防止程序可能出现的异常,在捕获异常的代码块中,如果前面有异常就不会执行后面的

try
{
	......	//可能产生异常的代码
}
catch( ExceptionName1 e )
{
	......	//当产生ExceptionName1型异常时的处置措施
}
catch( ExceptionName2 e )
{
...... 	//当产生ExceptionName2型异常时的处置措施
}  
[ finally{
......	 //无条件执行的语句,可写可不写,一定会执行
		}  ]

抛出异常  throws

   §声明抛出异常是Java中处理异常的第二种方式

可以main方法抛出异常,直接抛到java虚拟机了,程序中就不能处理

子类重写父类,子类不能抛出比父类更大的异常

用户自定义异常类

class MyException extends Exception {
   	private int idnumber;
 	public MyException(String message, int id) {
		super(message);
		this.idnumber = id;
 	} 
	public int getId() {
		return idnumber;
 	}
}
public class Test01{
        public void regist(int num) throws MyException {
 	if (num < 0) 
 	          throw new MyException("人数为负值,不合理",3);
	else
	          System.out.println("登记人数" + num );
        }
        public void manager() {
 	try {
	           regist(100);
 	} catch (MyException e) {
 	           System.out.print("登记失败,出错种类"+e.getId());	 	
	}
	System.out.print("本次登记操作结束");
       }
       public static void main(String args[]){
	Test8_6 t = new Test8_6();
	t.manager();
       }
}

集合

Java集合类存放于 java.util 包中,是一个用来存放对象的容器。

①、集合只能存放对象。比如你存一个 int 型数据 1 放入集合中,其实它是自动转换成 Integer 类后存入的, Java 中每一种基本类型都有对应的引用类型。
②、集合存放的是多个对象的引用,对象本身还是放在堆内存中。
③、集合可以存放不同类型,不限数量的数据类型。

Java 集合可分为 SetList Map 三种大体系

   Set:无序、不可重复的集合

   List:有序,可重复的集合

   Map:具有映射关系的集合

JDK5 之后,增加了泛型,Java 集合可以记住容器中对象的数据类型

HashSet

  

HashSet Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。我们大多数时候说的set集合指的都是HashSet

HashSet Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。

HashSet 具有以下特点:

   不能保证元素的排列顺序

   不可重复

   HashSet 不是线程安全的

   集合元素可以使 null

当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置

如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。

       Set set=new HashSet();
   //  Set<Object> set=new HashSet<Object>();//Object与上面的等价
        set.add("aa");//添加
        set.add(1);
        System.out.println(set);
        set.remove(1);//移除
        System.out.println(set);
        System.out.println(set.contains(1));//判断是否包含
        set.clear();//清空
        System.out.println(set);
        //使用遍历器
        set.add("q");
        set.add("qw");
        set.add("qwe");
        set.add("qwe");//set集合不存重复值
        set.add(null);
        set.add(true);
        Iterator iterator=set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //for each 迭代集合 推荐使用
        for (Object obj:set) {//把set每个值取出来赋值给obj,直到循环完成
            System.out.println(obj);
        }
        System.out.println(set.size());//获取集合的元素个数
        //如果想要集合存同样类型的集合,用泛型
        Set<String> stringSet=new HashSet<String>();//指定String集合的泛型,不能用其他的
        stringSet.add("sss");

TreeSet

TreeSet SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态

TreeSet 支持两种排序方法:自然排序和定制排序默认情况下,TreeSet 采用自然排序

自然排序

TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序排列

如果 this > obj, 返回正数 1
如果 this < obj, 返回负数 -1
如果 this = obj, 返回 0 ,则认为这两个对象相等
必须放入同样类的对象 .( 默认会进行排序 ) 否则可能会发生类型转换异常 . 我们可以使用泛型来进行限制
      //TreeSet自然排序
        Set<Integer> set = new TreeSet<Integer>();
        set.add(5);
        set.add(2);
        set.add(1);
        set.add(3);
        set.add(6);
        System.out.println(set);//运行结果:[1, 2, 3, 5]
        set.remove(5);
        set.contains(2);
//        set.clear();
        Iterator<Integer> iterator=set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //for each 迭代集合 推荐使用
        for (Object obj:set) {//把set每个值取出来赋值给obj,直到循环完成
            System.out.println(obj);
        }
        System.out.println(set.size());//获取集合的元素个数
        //如果想要集合存同样类型的集合,用泛型
        Set<String> stringSet=new TreeSet<String>();//指定String集合的泛型,不能用其他的
        stringSet.add("sss");
        System.out.println(stringSet);

定制排序

如果需要实现定制排序,则需要在创建 TreeSet 集合对象时,提供一个 Comparator 接口的实现类对象。由该 Comparator 对象负责集合元素的排序逻辑

public class Test2 {
    public static void main(String[] args) {
        Person p1=new Person("张三",20);
        Person p2=new Person("李四",16);
        Person p3=new Person("王五",29);
        Person p4=new Person("刘麻子",23);
        Set<Person> setp=new TreeSet<Person>(new Person());
        setp.add(p1);
        setp.add(p2);
        setp.add(p3);
        setp.add(p4);
        for (Person p:setp) {
            System.out.println(p.name+"  "+p.age);
        }
    }
}
 class  Person implements Comparator<Person> {//把对象存在TreeSet中,按照年龄排序
    int age;
    String name;
    public Person(){

    }
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    //正序排序 李四  16
    //张三  20
    //刘麻子  23
    //王五  29
//     public int compare(Person o1, Person o2) {//年龄正序排序
//         if (o1.age>o2.age){
//             return 1;
//         }else if ((o1.age<o2.age)){
//             return -1;
//         }else {
//             return 0;
//         }
//     }
     public int compare(Person o1, Person o2) {//年龄倒叙序排序
         if (o1.age>o2.age){
             return -1;
         }else if ((o1.age<o2.age)){
             return 1;
         }else {
             return 0;
         }
     }
 }

 

ListArrayList

List 代表一个元素有序、且可重复的集合,集合中的每个元素都有其对应的顺序索引

List 允许使用重复元素,可以通过索引来访问指定位置的集合元素。

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

List 集合里添加了一些根据索引来操作集合元素的方法

        List<String> list = new ArrayList<String>();
		list.add("b");//第一个,索引下标0
		list.add("d");//索引下标1
		list.add("c");//索引下标2
		list.add("a");//索引下标3
		list.add("d");//允许使用重复元素
		
		System.out.println(list);
		System.out.println(list.get(2));//通过索引来访问指定位置的集合元素
		
		list.add(1,"f");//在指定索引下标的位置插入数据
		System.out.println(list);
		
		List<String> l = new ArrayList<String>();
		l.add("123");
		l.add("456");
		
		list.addAll(2, l);//在指定索引下标的位置插入集合
		
		System.out.println(list);
		
		System.out.println(list.indexOf("d"));//获取指定元素在集合中第一次出现的索引下标
		System.out.println(list.lastIndexOf("d"));//获取指定元素在集合中最后一次出现的索引下标
		
		list.remove(2);//根据指定的索引下标移除元素
		System.out.println(list);
		
		list.set(1, "ff");//根据指定的索引下标修改元素
		System.out.println(list);
		
		//根据索引下标的起始位置截取一段元素形参一个新的集合,截取的时候,包含开始的索引不包含结束时的索引
		List<String> sublist =  list.subList(2, 4);//取索引下标在大于等于2小于4的元素
		
		System.out.println(sublist);
		
		System.out.println(list.size());//集合的长度

ArrayList Vector

Vector 是一个古老的集合,通常建议使用 ArrayList
ArrayList 是线程不安全的,而 Vector 是线程安全的。
即使为保证 List 集合线程安全,也不推荐使用 Vector

Map

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

Map<String, Integer> map = new HashMap<String, Integer>();
		map.put("b", 1);//添加数据
		map.put("c", 2);
		map.put("e", 2);
		System.out.println(map);

		System.out.println(map.get("b"));//根据key取值

		map.remove("c");//根据key移除键值对
		System.out.println(map);

		System.out.println(map.size());//map集合的长度

		System.out.println(map.containsKey("a"));//判断当前的map集合是否包含指定的key

		System.out.println(map.containsValue(10));//判断当前的map集合是否包含指定的value

//		map.clear();//清空集合
        

		Set<String> keys = map.keySet();//获取map集合的key的集合

		map.values();//获取集合的所有value值

		//遍历map集合,通过map.keySet();
		for(String key : keys){
			System.out.println("key: " + key + ", value: " + map.get(key));
		}

		//通过map.entrySet();遍历map集合
		Set<Map.Entry<String, Integer>> entrys = map.entrySet();
		for(Map.Entry<String, Integer> en : entrys){
			System.out.println("key: " + en.getKey() + ", value: " + en.getValue());
		}

 

HashMap & Hashtable

HashMap Hashtable Map 接口的两个典型实现类

区别:

Hashtable 是一个古老的 Map 实现类,不建议使用
Hashtable 是一个线程安全的 Map 实现,但 HashMap 是线程不安全的。
Hashtable 不允许使用 null 作为 key value ,而 HashMap 可以

与 HashSet 集合不能保证元素的顺序一样,Hashtable 、HashMap 也不能保证其中 key-value 对的顺序
Hashtable 、HashMap 判断两个 Key 相等的标准是:两个 Key 通过 equals 方法返回 true,hashCode 值也相等。
Hashtable 、相等的标准是:两个 Value 通过 equalHashMap 判断两个 Values 方法返回 true

TreeMap

TreeMap 存储 Key-Value 对时,需要根据 Key key-value 对进行排序。TreeMap 可以保证所有的 Key-Value 对处于有序状态。

TreeMap Key 的排序:

自然排序: TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
定制排序(了解):创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map Key 实现 Comparable 接口
      //TreeMap的自然排序是字典排序
        Map<Integer,String> map = new TreeMap<Integer, String>();
        map.put(4, "a");
        map.put(2, "a");
        map.put(3, "a");
        map.put(1, "a");

        System.out.println(map);

        Map<String,String> map1 = new TreeMap<String, String>();
        map1.put("b", "b");
        map1.put("c", "c");
        map1.put("d", "d");
        map1.put("a", "a");
        map1.put("ab", "ab");
        map1.put("1", "ab");
        map1.put("10", "ab");

        System.out.println(map1);
结果
{1=a, 2=a, 3=a, 4=a}
{1=ab, 10=ab, a=a, ab=ab, b=b, c=c, d=d}

操作集合的工具类:Collections

Collections 中提供了大量方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
排序操作:
reverse(List):反转 List 中元素的顺序
shuffle(List):对 List 集合元素进行随机排序
sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换

查找、替换

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

List<String> list = new ArrayList<String>();
		list.add("b");
		list.add("cd");
		list.add("ca");
		list.add("a");
		list.add("a");
		list.add("1");
		
		System.out.println(list);
		
		Collections.reverse(list);//反转 List 中元素的顺序
		System.out.println(list);
		
		Collections.shuffle(list);//对 List 集合元素进行随机排序
		System.out.println(list);
//		
		Collections.sort(list);//list集合字典升序排序
		System.out.println(list);
		
		System.out.println(Collections.frequency(list, "x"));//返回指定集合中指定元素的出现次数
		
		Collections.replaceAll(list, "b", "bb");//使用新值替换 List 对象的所有旧值
		
		System.out.println(list);
		
//		Collections.swap(list, 0, 4);//将指定 list 集合中的 i 处元素和 j 处元素进行交换
//		System.out.println(list);
		
//		System.out.println(Collections.max(list));
//		System.out.println(Collections.min(list));
//		
//		Student s1 = new Student(14,"张三");
//		Student s2 = new Student(12,"李四");
//		Student s3 = new Student(13,"王五");
//		Student s4 = new Student(11,"小六");
//		
//		List<Student> stus = new ArrayList<Student>();
//		stus.add(s1);
//		stus.add(s2);
//		stus.add(s3);
//		stus.add(s4);
//		
//		Student s = Collections.max(stus, new Student());
//		System.out.println(s.name + "," + s.age);
//		
//		Student ss = Collections.min(stus, new Student());
//		System.out.println(ss.name + "," + ss.age);
		
//		for(Student stu : stus){
//			System.out.println(stu.name + "," + stu.age);
//		}
//		
//		Collections.sort(stus, new Student());
//		System.out.println("-----------------------------");
//		for(Student stu : stus){
//			System.out.println(stu.name + "," + stu.age);
//		}
		
	}
}

class Student implements Comparator<Student>{
	int age;
	String name;
	
	public Student(){
		
	}
	
	public Student(int age,String name){
		this.age = age;
		this.name = name;
	}
	
	@Override
	public int compare(Student o1, Student o2) {//根据年龄升序排列对象
		if(o1.age > o2.age){
			return 1;
		}else if(o1.age < o2.age){
			return -1;
		}else{
			return 0;
		}

同步控制

Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题

Java泛型

解决数据类型的安全性问题,其主要原理是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明或实例化时只要指定好需要的具体的类型即可

Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。

泛型类

泛型接口

泛型方法

无返回值,有返回值,形参是可变参数的泛型方法

class Cc<E>{
	private E e;
	
	/**
	 * 静态方法的泛型方法
	 * @param t
	 */
	public static <T> void test3(T t){
		//在静态方法中,不能使用类定义泛型,如果要使用泛型,只能使用静态方法自己定义的泛型
//		System.out.println(this.e);
		System.out.println(t);
	}
	
	/**
	 * 无返回值的泛型方法
	 * @param s
	 */
	public <T> void test(T s){
		//在类上定义的泛型,可以在普通的方法中使用
		System.out.println(this.e);
		T t = s;
	}
	
	/**
	 * 有返回值的泛型方法
	 * @param s
	 */
	public <T> T test1(T s){
		return s;
	}
	
	/**
	 * 形参为可变参数的泛型方法
	 * @param strs
	 */
	public <T> void test2(T... strs){
		for(T s : strs){
			System.out.println(s);
		}
	}
}

测试


		Cc<Object> c = new Cc<Object>();
		c.test("xxx");
		//泛型方法,在调用之前没有固定的数据类型
		//在调用时,传入的参数是什么类型,就会把泛型改成什么类型
		//也就是说,泛型方法会在调用时确定泛型距离数据类型
		Integer i = c.test1(2);//传递的参数是Integer,泛型就固定成Integer,返回值就是Integer
		Boolean b = c.test1(true);//传递的参数是Boolean,泛型就固定成Boolean,返回值就是Boolean

通配符

有限制的通配符

举例:
 •<? extends Person>     (无穷小 , Person]
 只允许泛型为Person及Person子类的引用调用
•<? super Person >      [Person , 无穷大)
 只允许泛型为Person及Person父类的引用调用
•<? extends Comparable>
只允许泛型为实 现Comparable接口的实现类的引用调用

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

public class Test2 {
	public static void main(String[] args) {
		Dd d = new Dd();
		List<String> l1 = new ArrayList<String>();
		d.test(l1);
		
		List<Integer> l2 = new ArrayList<Integer>();
		d.test(l2);
		
		List<C1> lc = new ArrayList<C1>();
		d.test1(lc);
		
		List<D1> ld = new ArrayList<D1>();
		d.test1(ld);
		
//		List<B3> lb = new ArrayList<B3>();
//		d.test1(lb);
		
		d.test2(lc);
		List<A1> la = new ArrayList<A1>();
		d.test2(la);
		
//		d.test2(ld);
		
		List<IAImpl> lia = new ArrayList<IAImpl>();
		d.test3(lia);
		
//		d.test3(la);
	}
}

class Dd{
	public void test(List<?> list){//test方法需要一个list集合的参数,不确定list集合到底是存的数的类型是什么
		
	}
	
	public void test1(List<? extends C1> list){//list参数的元素数据类型是C1及其子类
		
	}
	
	public void test2(List<? super C1> list){//list参数的元素数据类型是C1及其父类
		
	}
	
	public void test3(List<? extends IA> list){//list参数的元素数据类型是IA的实现类
		
	}
}

class A1{}

class B3 extends A1{}

class C1 extends B3{}

class D1 extends C1{}

interface IA{}

class IAImpl implements IA{}

 

enum 定义枚举类

枚举类对象的属性不应允许被改动 , 所以应该使用 private final 修饰
枚举类使用 private final 修饰的属性应该在构造器中为其赋值
若枚举类显式的定义了带参数的构造器 , 则在列出枚举值时也必须对应的传入参数
Annotation( 注解 )
 
JDK 5.0 开始 , Java 增加了对元数据 ( MetaData ) 的支持 , 也就是 Annotation( 注释 )
Annotation 其实就是代码里的特殊标记 , 这些标记可以在编译 , 类加载 , 运行时被读取 , 并执行相应的处理 . 通过使用 Annotation, 程序员可以在 不改变原有逻辑的情况下 , 在源文件中嵌入一些补充信息 .
Annotation 可以像修饰符一样被使用 , 可用于修饰包 , , 构造器 , 方法 , 成员变量 , 参数 , 局部变量的声明 , 这些信息被保存在 Annotation “name=value” 对中 .
Annotation 能被用来为程序元素 ( , 方法 , 成员变量等 ) 设置元数据
使用 Annotation 时要在其前面增加 @ 符号 , 把该 Annotation 当成一个修饰符使用 . 用于修饰它支持的程序元素
三个基本的 Annotation:
@Override: 限定重写父类方法 , 该注释只能用于方法
@Deprecated: 用于表示某个程序元素 ( , 方法等 ) 已过时
@ SuppressWarnings : 抑制编译器警告 .

 

 
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;

public class Test4 {
	public static void main(String[] args) {
		new TestB().test1();
		
		@SuppressWarnings({ "rawtypes", "unused" })
		List list = new ArrayList();
	}
}


class TestA{
//	@TestAnn()
	public void test(){
		
	}
}

class TestB extends TestA{
	
	@TestAnn(id=100,desc="姓名")
	String name;
	
	@Override
	public void test() {
		// TODO Auto-generated method stub
		super.test();
	}
	
	@Deprecated
	public void test1(){
		
	}
}

@Target(ElementType.FIELD)//这个注解类是给其他类的属性做注解
@Retention(RetentionPolicy.RUNTIME)//定义注解的声明周期
@Documented
@interface TestAnn{
	public int id() default 0;
	
	public String desc() default "";
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值