任何一种程序设计语言设计的程序在运行时都有可能出现错误,例如除数为0,数组下标越界,要读写的文件不存在等等。
捕获错误最理想的是在编译期间,但有的错误只有在运行时才会发生。
对于这些错误,一般有两种解决方法:
在Java中,将程序执行中发生的不正常情况称为"异常"。
异常是对问题的描述,将问题封装成类
异常可分为两类:
程序员只能处理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");
}
}
特点: 异常体系中的所有类都具备可抛性,即都可以被try…catch处理,只有异常体系具备这个特点。
异常分为两种:
异常处理是通过try-catch-finally语句实现的,其中finally可有可无。
try {
}catch(){
}
-------------------------
try {
}finally{
}
-------------------------
try {
需要被检测的代码;
}catch() {
处理异常的代码;
}finally {
一定会执行的代码;
}
注意:
1. 语法格式:
修饰符 返回值类型 方法名() throws xxxException/Exception{…}
2. 注意:
抛出异常后,要在调用该方法时捕获异常,最迟要在main方法上捕获异常,若一直抛出不捕获,该异常抛给JVM,程序将不能处理该异常,但程序可以执行。
2. throw、throws的用法:
当方法内有throw抛出异常时,若在方法内并未进行try catch处理,则必须在方法名上throws该异常类,否则编译失败(RuntimeException除外)。当调用者使用了抛出异常的方法时,有两种处理办法,一是try catch处理异常,二是继续抛出异常。
处理方式有两种:try catch(可以解决)或throws(不能解决)。
当调用到抛出异常的代码时,抛出几个异常就要处理几个异常,即一个try对应多个catch。
有多个catch时,父类的catch要放在最下面。
catch内要定义有针对性的处理措施,不要简单定义e.printStackTrace()或输出语句,也不要什么都不写。
当捕获到的异常本功能不能处理时,可以继续在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:
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) {
}
}
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: 电脑死机, 请更换另一台电脑
*/
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 集合可分为 Set、List 和 Map 三种:
集合提供了泛型,Java 集合可以指定存入集合的对象的数据类型。
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);
}
}
}
注意:
Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题。
HashSet 是 Set 接口的典型实现,HashSet 按 Hash 算法来存储集合中的元素。
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());
}
}
}
方法 | 意义 |
---|---|
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 如何保证存入数据的唯一性?
与HashSet相同。
自然排序:基本数据类型、String、包装类存入TreeSet 时的默认排序方式,按字母顺序升序排序。
定制排序:TreeSet 中存入自己定义的对象时,规定的数据排列方式。
两种实现方法:
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 调用contains()、remove()方法时(需要判断元素是否相同),依据的是元素的equals()方法。
注意:元素下标从0开始。
方法 | 意义 |
---|---|
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
}
}
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());
}
}
}
基本方法与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;
}
}
方法 | 意义 |
---|---|
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 |
获取map集合的键值对(key, value)集合 |
Map.Entry提供的方法 | 意义 |
---|---|
getKey() | 获取key |
getValue() | 获取value |
setValue(V value) | 用指定的值替换当前key的value值 |
注意:
Map集合添加元素时,若两次添加的key值相同,则新value代替旧value,put()方法会返回被覆盖的值。
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);
}
}
}
与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();//转换为字符串
}
}
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)))
}
}