JAVA 笔记

时间:2023-12-27 17:35:13

一、Java基础以及面向对象编程
1、float类型的数自动转换成double类型时,可能会出现前后不相等的情况,因为有些数不能够用有限的二进制位精确表示。
2、右移
>>右移,左边空出位以符号位填充
>>>右移,左边空出位以0填充
3、计算阶乘

public class Factorial {
public Factorial(){ }
public long getFactorial(int n){
if((n<0)||(n>17)){
return -1;
}else if(n==0 || n==1){
return 1;
}else{
long result=n;
do{
result *=(--n);
}while(n>1);
return result;
}
}
}

4、System.exit(0) 该方法关闭Java虚拟机,退出应用程序,当exit方法的参数为0时表示程序正常退出,为其他值时异常退出。
5、重写equals、clone、hashCode方法
这几个方法在Object类中都是基于对象的地址来实现的,如果要实现符合实际意义的方法,则需要在Object的子类中进行重写。这里以复数类为例:
(1)重写equals方法
先判断传入对象与现有对象是否同一类,再对同一类的传入对象比较属性。

    @Override
public boolean equals(Object obj) {
if(obj==null){
return false;
}
if(obj instanceof ComplexNumber){
ComplexNumber b=(ComplexNumber)obj;
if((this.realPart == b.realPart) && (this.imaginaryPart==b.imaginaryPart)){
return true;
}else{
return false;
}
}else{
return false;
}
}

(2)重写hashCode方法
找到一个能够代表对象的Key,如果这个key是int类型,可以直接返回该key,如果其他类型,则返回该key的hashCode。

    @Override
public String toString() {
return "ComplexNumber{" + "realPart=" + realPart + ", imaginaryPart=" + imaginaryPart + '}';
} @Override
public int hashCode() {
return this.toString().hashCode();
}

(3)重写clone方法
首先,类要实现Cloneable方法,然后再重写clone方法。实现时,先调用父类的clone方法,然后将现有对象的属性值赋给新对象。

    @Override
protected Object clone() {
try{
ComplexNumber newObject=(ComplexNumber) super.clone();
newObject.setRealPart(this.realPart);
newObject.setImaginaryPart(this.imaginaryPart);
return newObject;
}catch(CloneNotSupportedException e){
e.printStackTrace();
return null;
}
}

6、Java在传递参数时,如果参数是对象类型,则将“参数的引用”复制之后传给方法。
7、System的gc方法通知Java虚拟机进行垃圾回收,但何时回收由虚拟机决定,进行垃圾回收时,虚拟机会调用对象的finalize方法。
8、对于每个类,Java虚拟机只加载一次,加载时,对类的静态方法、静态变量、静态初始化块进行初始化。只有在新建一个对象时,才会按先父类后子类的顺序初始化类的初始化块、构造函数。
9、方法和变量在继承时的覆盖和隐藏
(1)同名的实例方法被覆盖,同名的类方法(静态方法)被隐藏。
(2)隐藏和覆盖的区别:子类对象转换成父类后,能够访问父类被隐藏的变量和方法,但不能访问被覆盖的变量和方法。
10、排序
(1)接口

public interface ISortNumber {
/**
* 升序排序
* @param intArray
* @return
*/
public int[] sortASC(int[] intArray);
}

(2)选择排序

public class SelectionSort implements ISortNumber{

    public SelectionSort() {
} @Override
public int[] sortASC(int[] intArray) {
if(intArray==null){
return null;
} int[] srcDatas=(int[])intArray.clone();
int size=srcDatas.length;
for(int i=0;i<size;i++){
for(int j=i;j<size;j++){
if(srcDatas[i]>srcDatas[j]){
swap(srcDatas,i,j);
}
}
}
return srcDatas;
} private void swap(int[] data,int src,int dest){
int temp=data[src];
data[src]=data[dest];
data[dest]=temp;
}
}

(3)冒泡排序

public class BubbleSort implements ISortNumber{

    public BubbleSort() {
} @Override
public int[] sortASC(int[] intArray) {
if(intArray==null){
return null;
} int[] srcDatas=(int[]) intArray.clone();
boolean changedPosition=true;
int comparedTimes=0;
int maxComparedTimes=srcDatas.length-1; while((comparedTimes<maxComparedTimes) && (changedPosition)){
for(int i=0;i<(maxComparedTimes-comparedTimes);i++){
changedPosition=false;
if(srcDatas[i]>srcDatas[i+1]){
swap(srcDatas,i,i+1);
changedPosition=true;
}
}
comparedTimes++;
}
return srcDatas;
} private void swap(int[] data,int src,int dest){
int temp=data[src];
data[src]=data[dest];
data[dest]=temp;
} }

(4)线性插值排序

public class LinearInsertSort implements ISortNumber{

    public LinearInsertSort() {
} @Override
public int[] sortASC(int[] intArray) {
if(intArray==null){
return null;
}
int[] srcDatas=(int[])intArray.clone();
int size=srcDatas.length;
int temp=0;
int index=0;
for(int i=1;i<size;i++){
temp=srcDatas[i];
index=i;
while((index>0) && (temp<srcDatas[index-1])){
srcDatas[index]=srcDatas[index-1];
index--;
}
}
return srcDatas;
} }

(5)快速排序

public class QuickSort implements ISortNumber{

    public QuickSort() {
} @Override
public int[] sortASC(int[] intArray) {
if(intArray==null){
return null;
}
int[] srcDatas=(int[])intArray.clone(); return this.quickSort(srcDatas,0,srcDatas.length-1);
} private int[] quickSort(int[] srcDatas,int first,int last){
if(first<last){
int pos=partion(srcDatas,first,last);
quickSort(srcDatas,first,pos-1);
quickSort(srcDatas,pos+1,last);
}
return srcDatas;
} //根据数组的第一个数分治
//比第一个数大的往后排,比第一个数小的往前排
private int partion(int[] srcDatas,int first,int last ){
int temp=srcDatas[first];
int pos=first;
for(int i=first+1;i<=last;i++){
if(srcDatas[i]<temp){
pos++;
swap(srcDatas,pos,i);
}
}
swap(srcDatas,first,pos);
return pos;
} private void swap(int[] data,int src,int dest){
int temp=data[src];
data[src]=data[dest];
data[dest]=temp;
}
}

10、Singleton模式

(1)模式1

public class SingletonA {
private static int id=1;
private static SingletonA instance=new SingletonA();
private SingletonA() { } public static SingletonA getInstance(){
return instance;
} public synchronized int getId(){
return id;
} }

(2)模式2(lazy initialization)

public class SingletonA {
private static int id=1;
private static SingletonA instance=null;
private SingletonA() { } public static SingletonA getInstance(){
if(instance==null){
instance=new SingletonA();
}
return instance;
} public synchronized int getId(){
return id;
} }

在getInstance方法声明中使用synchronized(同步)关键字,以保证同一时刻只有一个进程进入该方法。保证只创建一个对象。

11、Factory模式
(1)用一个接口抽象产品功能,所有具体的产品都实现该接口
(2)Factory类定义一个创建产品的方法,参数为产品的具体类型,返回一个产品接口对象。用户通过产品接口使用产品功能。
如下面的例子,该Factory类可以根据用户需求创建不同的用于排序的产品。

public class Factory {
public static final String SELECTION_SORT="selection";
public static final String BUBBLE_SORT="bubble";
public static final String LINEARINSERT_SORT="linearinsert";
public static final String QUICK_SORT="quick"; public static ISortNumber getOrderNumber(String id){
if(SELECTION_SORT.equalsIgnoreCase(id)){
return new SelectionSort();
}else if(BUBBLE_SORT.equalsIgnoreCase(id)){
return new BubbleSort();
}else if(LINEARINSERT_SORT.equalsIgnoreCase(id)){
return new LinearInsertSort();
}else if(QUICK_SORT.equalsIgnoreCase(id)){
return new QuickSort();
}else{
return null;
}
} }

12、Adapter类

public class Printer {
public static void printIntArray(int[] array){
if(array!=null){
for(int i=0;i<array.length;i++){
System.out.print(array[i]+" ");
}
System.out.println();
}
}
} public class PrinterAdapter extends Printer implements ISortNumber{
private ISortNumber mySort; public PrinterAdapter(ISortNumber mySort) {
super();
this.mySort = mySort;
} @Override
public int[] sortASC(int[] intArray) {
if(this.mySort!=null){
return this.mySort.sortASC(intArray);
}
return null;
} }

PrinterAdapter是Adapter,将Printer和ISortNumber进行适配,具有两者定义的所有功能。
ISortNumber是Adaptee。Adapter的构造方法中串入一个具体的Adaptee对象,在实现Adaptee接口定义的方法中,调用Adaptee的相应方法。
Printer是目标类。

二、数字
13、数字与数字封装类的相互转换
(1)byte与Byte

byte b1=5;
Byte b2=new Byte(b1); //或者 Byte b2=Byte.valueOf(b1);
byte b3=b2.byteValue();

(2)int与Integer

int i1=5;
Integer i2=new Integer(i1);//或者 Integer i2=Integer.valueof(i1);
int i3=i2.intValue();

14、格式化数字,使用DecimalFormat类。

DecimalFormat df=new DecimalFormat();
double data=1234.4650238903;
String pattern="0.0";//显示格式
df.applyPattern(pattern);
String str=df.format(data);//格式化后为1234.5
//pattern ="00000.000 kg" 格式化为001234.465 kg
//pattern ="##000.000 kg" 格式化为1234.465 kg
//pattern ="-000.000" 格式化为-1234.465
//pattern ="-0,000.000" 格式化为-1,234.465
//pattern ="0.00E000" 格式化为1.23E003
//pattern ="0.00%" 格式化为123446.50%
//pattern ="0.00\u2030" 格式化为1234465.02‰,显示为千分数

15、数字的舍入
用BigDecimal类的setScale方法来实现,支持不同的舍入模式。
16、数制的转换
Integer或Long的toString(int i,int radix)、toBinaryString()、toOctalString()、toHexString()等方法。
17、生成随机数,用Random类来实现。
18、高精度运算
使用BigInteger和BigDecimal类。
下例,计算阶乘。

     public BigInteger getFactorial(int n){
if((n<0)||(n>17)){
return new BigInteger("-1");
}else if(n==0 || n==1){
return new BigInteger("1");
}else{
BigInteger result=new BigInteger("n");
do{
result.multiply(new BigInteger(new Integer(--n).toString()));
}while(n>1);
return result;
}
}

BigInteger和BigDecimal类都是不可变的,每一步运算都会产生一个新对象,不适合大量的数学运算。这两个类常常用在商业计算的精确大整数和小数。
要获得精确小数,应使用String来构造BigDecimal,避免使用double来构造,因为double类型并不精确。
从数值上比较两个BigDecimal的值时,应使用compareTo方法,而不是equals方法,因为后者会认为0.10和0.1不相等。

三、数组与集合
1、Arrays
填充数组,

int[] array0=new int[10];
Arrays.fill(array0,3);//给数组所有元素赋值为5
Arrays.fill(array0,2,5,7);//给array0[2]~array0[4]赋值为7

排序

Arrays.sort(array0,2,7);//将array0[2]~array0[6]排序
Arrays.sort(array0);//整个数组排序

2、求质数

    /**
* 用筛选法求range范围内的质数
* @param range 范围的上限
* @return
*/
private boolean[] sieve(int range){
if(range<0){
return null;
} boolean[] isPrime=new boolean[range+1];
isPrime[1]=false;
Arrays.fill(isPrime, 2, range+1, true); int n=(int)Math.sqrt(range);
for(int i=1;i<=n;i++){
if(isPrime[i]){
//如果i是质数,则i的倍数不是质数
for(int j=2*i;j<=range;j+=i){
isPrime[j]=false;
}
}
}
return isPrime;
}

3、动态调整数组的长度
新建一个新的数组,然后将原数组的数据拷贝到新数组中。
Integer[] result=new Integer[src.length+length];
System.arraycopy(src,0,result,0,src.length);
4、矩阵
用double二维数组创建矩阵,并实现矩阵的加减乘除算法。

 public class Matrix implements Cloneable{
private double[][] matrixData; public Matrix() {
this.init();
} public Matrix(double[][] matrixData) {
if(!this.canConvert2Matrix(matrixData)){
this.init();
} else{
this.matrixData = this.cloneArray(matrixData);
}
} private void init(){
this.matrixData=new double[][]{
{1.0,0.0,0.0},
{0.0,1.0,0.0},
{0.0,0.0,1.0}};
} private boolean canConvert2Matrix(double[][] matrixData){
if(matrixData==null){
return false;
}
for(int i=0;i<matrixData.length-1;i++){
if(matrixData[i].length!=matrixData[i+1].length){
return false;
}
}
return true;
} private double[][] cloneArray(double[][] src){
if(src==null){
return null;
}
return (double[][]) src.clone();
}
/**
* 矩阵相加
* @param b
* @return
*/
public Matrix add(Matrix b){
if(b==null){
return null;
} Matrix c=null;
double[][] bData=b.getMatrixData();
if(this.matrixData.length!=bData.length
|| this.matrixData[0].length!=bData[0].length){
System.out.println("两个矩阵长度不一致,不能相加");
return c;
} double[][] cData=new double[this.matrixData.length][this.matrixData[0].length];
for(int i=0;i<this.matrixData.length;i++){
for(int j=0;j<this.matrixData[0].length;j++){
cData[i][j]=this.matrixData[i][j]+bData[i][j];
}
}
c=new Matrix(cData);
return c; } /**
* 矩阵相减
* @param b
* @return
*/
public Matrix sub(Matrix b){
if(b==null){
return null;
} Matrix c=null;
double[][] bData=b.getMatrixData();
if(this.matrixData.length!=bData.length
|| this.matrixData[0].length!=bData[0].length){
System.out.println("两个矩阵长度不一致,不能相减");
return c;
} double[][] cData=new double[this.matrixData.length][this.matrixData[0].length];
for(int i=0;i<this.matrixData.length;i++){
for(int j=0;j<this.matrixData[0].length;j++){
cData[i][j]=this.matrixData[i][j]-bData[i][j];
}
}
c=new Matrix(cData);
return c; } /**
* 矩阵数乘
* @param num
* @return
*/
public Matrix multiplyNum(double num){
double[][] cData=new double[this.matrixData.length][this.matrixData[0].length];
for(int i=0;i<this.matrixData.length;i++){
for(int j=0;j<this.matrixData[0].length;j++){
cData[i][j]=this.matrixData[i][j] * num;
}
}
return new Matrix(cData);
} /**
* 矩阵乘法
* @param b
* @return
*/
public Matrix multiply(Matrix b){
if(b==null)
return null;
double[][] bData=b.getMatrixData();
if(this.matrixData[0].length!=bData.length){
System.out.println("矩阵的A的列数不等于矩阵B的行数,不能相乘");
return null;
}
double[][] cData=new double[this.matrixData.length][bData[0].length];
for(int i=0;i<this.matrixData.length;i++){
for(int j=0;j<bData[0].length;j++){
cData[i][j]=0;
for(int k=0;k<this.matrixData[0].length;k++){
cData[i][j]+=this.matrixData[i][k]*bData[k][j];
}
}
}
return new Matrix(cData);
} /**
* 矩阵除法
* @param b
* @return
*/
public Matrix divide(Matrix b){
if(b==null){
return null;
}
if(!this.isSquareMatrix()
|| (!b.isSquareMatrix())
|| (this.matrixData.length!=b.getMatrixData().length)){
System.out.println("不能相除");
return null;
}
Matrix c=b.inverseMatrix();
if(c!=null)
return this.multiply(c);
else{
System.out.println("不能相除");
return null;
}
}
/**
* 逆矩阵
* @return
*/
public Matrix inverseMatrix() {
if(!this.isSquareMatrix()){
System.out.println("不是方阵,不能求逆");
return null;
} Matrix tempM=this.appendUnitMatrix();
double[][] tempData=tempM.getMatrixData();
int line=0;
double bs=0;
double swap=0;
for(int i=0;i<tempData.length;i++){
if(tempData[i][i]==0){
if(++line>=tempData.length){
System.out.println("没有逆矩阵");
return null;
}
for(int j=0;j<tempData[0].length;j++){
swap=tempData[i][j];
tempData[i][j]=tempData[line][j];
tempData[line][j]=swap;
}
continue;
} if(tempData[i][i]!=1){
bs=tempData[i][i];
for(int j=tempData[0].length-1;j>=0;j--){
tempData[i][j]/=bs;
}
for(int iNow=i+1;iNow<tempData.length;iNow++){
for(int j=tempData[0].length-1;j>=i;j--){
tempData[iNow][j]-=tempData[i][j]*tempData[iNow][i];
}
}
}
}
//将左边矩阵变为单位矩阵
for(int i=0;i<tempData.length-1;i++){
for(int iNow=i;iNow<tempData.length-1;iNow++){
for(int j=tempData[0].length-1;j>=0;j--){
tempData[i][j]-=tempData[i][iNow+1]*tempData[iNow+1][j];
}
}
} //右边部分为逆矩阵
double[][] cData=new double[this.matrixData.length][this.matrixData[0].length];
for(int i=0;i<this.matrixData.length;i++){
for(int j=0;j<this.matrixData[0].length;j++){
cData[i][j] =tempData[i][j+this.matrixData[0].length];
}
}
return new Matrix(cData);
}
/**
* 给矩阵右边加上单位矩阵
* @return
*/
private Matrix appendUnitMatrix(){
double[][] cData=new double[this.matrixData.length][this.matrixData[0].length*2];
for(int i=0;i<this.matrixData.length;i++){
for(int j=0;j<this.matrixData[0].length*2;j++){
if(j<this.matrixData[0].length){
cData[i][j]=this.matrixData[i][j];
}else{
if((j-this.matrixData[0].length)==i){
cData[i][j]=1.0;
}else{
cData[i][j]=0.0;
}
}
}
}
return new Matrix(cData);
} /**
* 转置矩阵
* @return
*/
public Matrix transposeMatrix(){
double[][] cData=new double[this.matrixData[0].length][this.matrixData.length];
for(int i=0;i<this.matrixData[0].length;i++){
for(int j=0;j<this.matrixData.length;j++){
cData[i][j]=this.matrixData[j][i];
}
}
return new Matrix(cData);
} /**
* 矩阵是否为方阵
* @return
*/
public boolean isSquareMatrix(){
if(this.matrixData.length==this.matrixData[0].length){
return true;
}
return false;
} public double[][] getMatrixData(){
return this.cloneArray(this.matrixData);
} public void setMatrixData(double[][] matrixData){
if(this.canConvert2Matrix(matrixData)){
this.matrixData=this.cloneArray(matrixData);
}
} @Override
public String toString() {
DecimalFormat df=new DecimalFormat("0.00");
StringBuffer sb=new StringBuffer("");
for(int i=0;i<this.matrixData.length;i++){
for(int j=0;j<this.matrixData[0].length;j++){
sb.append(df.format(this.matrixData[i][j])).append(" ");
}
sb.append("\n");
}
return sb.toString();
} @Override
public int hashCode() {
return this.toString().hashCode();
} @Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Matrix other = (Matrix) obj;
if (!Arrays.deepEquals(this.matrixData, other.matrixData)) {
return false;
}
return true;
} @Override
protected Object clone(){
try{
Matrix matrix=(Matrix) super.clone();
matrix.setMatrixData(this.matrixData);
return matrix;
}catch(CloneNotSupportedException e){
}
return null;
}
}

5、ArrayList、Vector和LinkedList
(1)ArrayList、Vector都是用数组实现,不同的是Vector支持线程同步
(2)LinkedList使用链表结构存储数据,方便操作列表头和列表尾元素。
(3)可以为List生成ListIterator,支持双向遍历。
6、生成不重复的随机数序列
(1)排除法
如果新生成的数字不包含在结果列表中,则将数字添加到列表,否则,重新生成随机数。
(2)筛选法
将所有可能的数字放到候选列表中,将生成的随机数k作为下标,对应的候选列表中的数字添加到结果列表中,并从候选列表中删除。
7、用LinkedList可以方便地实现Queue
8、对List进行排序,用Collections.sort()方法,可以设置自定义的比较器(实现Comparator接口)。
9、HashSet
采用散列函数对元素进行排序。存入HashSet中的对象必须定义hashCode方法。
10、TreeSet
采用红黑树的数据结构进行排序,可以提取有序的序列。存入TreeSet中的自定义类对象需要实现Comparable接口并定义compareTo方法。
11、LinkedHashSet
使用链表维护元素的插入次序。元素的次序就是插入时的次序。
12、数组、List和Set之间的相互转化
(1)List转化为数组

String[] strArray=(String[])list.toArray(new String[list.size()]);

(2)Set转化为数组

String[] strArray=(String[])set.toArray(new String[set.size()]);

(3)数组转化为List

list=Arrays.asList(strArray);

(4)数组转化为Set,先转为List,再构造Set

set=new HashSet(Arrays.asList(strArray));

13、Map 键值对存储
(1)HashMap
不支持线程同步,键或值可以为null。
(2)HashTable
键或值都不能为null。支持线程同步。
(3)LinkedHashMap
保存记录的插入次序。
(4)TreeMap
记录按照Key来排序。
14、对Map排序
(1)其他Map转换成TreeMap,便可以进行按Key排序。
(2)TreeMap默认升序排列,可以指定比较器。
15、Properties属性文件
能从输入流(文件)中获取键值对信息,也可以将键值对信息存放到输出流(文件)中。

Properties props=new Properties();
//存放数据
props.setProperty("name","zhangsan");
//读取数据
String str=props.getProperty("name");
//保存到输出流
FileOutputStream out=new FileOutputStream("C:/test.properties");
props.store(out,"test");
out.close();
//从输出流中加载数据
Properties newProps=new Properties();
FileInputStream in=new FileInputStream("C:/test.properties");
newProps,load(in);
in.close();

四、字符串
1、String是不变类,修改String会得到新的String对象,如果要频繁修改字符串,应使用StringBuilder类。
2、IP地址转换为整数

     public static long ipToLong(String strIP){
long[] ip=new long[4];
int position1=strIP.indexOf(".");
int position2=strIP.indexOf(".",position1+1);
int position3=strIP.indexOf(".",position2+1);
ip[0]=Long.parseLong(strIP.substring(0, position1));
ip[1]=Long.parseLong(strIP.substring(position1+1, position2));
ip[2]=Long.parseLong(strIP.substring(position2+1, position3));
ip[3]=Long.parseLong(strIP.substring(position3+1)); return (ip[0]<<24)+(ip[1]<<16)+(ip[2]<<8)+ip[3];
} public static String longToIP(long longIP){
StringBuilder sb=new StringBuilder("");
sb.append(String.valueOf(longIP>>>24)).append(".");
sb.append(String.valueOf((longIP&0x00FFFFFF)>>>16)).append(".");
sb.append(String.valueOf((longIP&0x0000FFFF)>>>8)).append(".");
sb.append(String.valueOf(longIP&0x000000FF));
return sb.toString();
}

3、更改字符串的编码
先调用String的getBytes方法对字符串进行解码,再用得到的字节数组和新的字符编码构造一个新的String对象。
4、对字符串进行MD5编码
MD5是一种不可逆的加密方式,常用于管理账户信息数据库,数据库存储的是用户密码的MD5编码,这样可以防止用户的密码信息被管理员知道。

    public static String encodeByMD5(String originString){
String[] hexDigits={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};
if(originString!=null){
try{
MessageDigest md=MessageDigest.getInstance("MD5");
byte[] result=md.digest(originString.getBytes()); StringBuilder sb=new StringBuilder();
for(int i=0;i<result.length;i++){
int n=result[i];
if(n<0)
n=256+n;
int d1=n/16;
int d2=n%16;
sb.append(hexDigits[d1]+hexDigits[d2]);
}
return sb.toString();
}catch(Exception e){ }
}
return null;
}

5、制作命令行程序
难点在于解析命令行参数,可以使用Apache组织的cli项目的类库来完成。
6、StringTokenizer可以使字符串分写成多个标记。
7、使用正则表达式操作字符串
(1)java.util.regex.Pattern类 对正则表达式字符串进行编译
(2)java.util.regex.Matcher类,通过解释Pattern对字符串进行匹配,find方法返回查找匹配的结果,matches方法返回精确匹配的结果。
8、使用正则表达式验证电话号码格式

public static boolean isMatch(String phoneNum){
String patternStr="^([0-9]{3}-?[0-9]{8}) |([0-9]{4}-?[0-9]{7})$";
if(phoneNum!=null){
return phoneNum.matches(patternStr);
}
return false;
}

五、异常处理
1、避免使用异常
可以提前检测语句的使用条件,避免异常出现
2、不要为每个可能出现异常的语句单独设置try catch,尽量将这些语句都放在一个try块中。
3、避免在方法中抛出或捕获RuntimeException和Error
4、尽量catch具体的异常,不要总是catch Exception
5、不能处理的异常要往外抛
6、不要在循环体中使用try...catch

六、线程
1、线程的互斥
在某一个时刻,只允许一个线程访问对象的临界区
。如果一个对象有多个方法都要修改同一个变量的值,应将这些方法置为synchronized。
2、线程协作
wait、notify、notifyAll等关键字必须放在synchronized代码块中。

static class Printer extends Thread{
Vector task=new Vector();
boolean running=false;
public void start(){
this.running=true;
super.start();
} @Override
public void run() {
try{
while(running){
synchronized(this){
while((task.size()==0)&&running){
//如果任务为空,线程允许运行,则等待任务
//进入等待状态,释放对象锁
wait();
}
}
//执行任务
System.out.println("print the task:"+task.remove(0));
}
}catch(InterruptedException e){
e.printStackTrace();
}
}
//添加打印任务
public void adddTask(String str){
synchronized(this){
this.task.add(str);
//唤醒等待的线程
notify();
}
}
//停止线程
public void stopPrinter(){
this.running=false;
synchronized(this){
//唤醒其他等待的线程
notify();
}
}
}

3、join
调用子线程的join方法,表示当前线程必须等待子线程运行结束,才能继续运行。
4、消费者与生产者
用线程模拟消费者和生产者,不断从仓库类中消费/生产产品。
在仓库类中,消费产品时,如果产品数量为0,则wait,使消费线程等待,当有新产品存入时,notify,唤醒等待的消费线程。同理,生产产品时,如果产品数量达到上限,则wait,使生产线程等待,当有产品被消费后,notify,唤醒等待的生产线程。
注意:调用某个对象的wait、notify、notifyAll等方法时,必须用synchronized先获得对象锁,否则会抛出IllegalMonitorStateException异常。

 //(1)产品
public class Product {
private String name; public Product(String name) {
this.name = name;
}
}
//(2)消费者线程
public class Consumer extends Thread {
private Warehouse warehouse;
private boolean running=false; public Consumer(Warehouse warehouse, String name) {
super(name);
this.warehouse = warehouse;
} public boolean isRunning() {
return running;
} @Override
public synchronized void start() {
this.running=true;
super.start();
} @Override
public void run() {
Product product;
try{
while(running){
product=warehouse.getProduct();
sleep(500);
}
}catch(InterruptedException e){
e.printStackTrace();
}
} public void stopConsumer(){
synchronized(warehouse){
this.running=false;
warehouse.notifyAll();
}
}
}
//(3)生产者线程
public class Producer extends Thread{ private Warehouse warehouse;
private static int productName=0;
private boolean running=false; public Producer(Warehouse warehouse, String name) {
super(name);
this.warehouse = warehouse;
} public boolean isRunning() {
return running;
} @Override
public synchronized void start() {
this.running=true;
super.start();
} @Override
public void run() {
Product product;
try{
while(running){
product=new Product("pro"+(++productName));
this.warehouse.storageProduct(product);
sleep(300);
}
}catch(InterruptedException e){
e.printStackTrace();
}
} public void stopProducer(){
synchronized(warehouse){
this.running=false;
warehouse.notifyAll();
}
} }
//(4)仓库类
public class Warehouse {
private static int CAPACITY=11;//仓库容量
private Product[] products; private int front=0;//当前第一个未被消费的产品下标
private int rear=0;//当前最后一个未被消费的产品下标+1; public Warehouse() {
this.products = new Product[CAPACITY];
} public Warehouse(int capacity) {
this();
if(capacity>0){
CAPACITY=capacity+1;
this.products = new Product[CAPACITY];
}
} public Product getProduct() throws InterruptedException {
synchronized(this){
boolean consumerRunning=true;
Thread currentThread=Thread.currentThread();
if(currentThread instanceof Consumer){
consumerRunning=((Consumer)currentThread).isRunning();
}else{
return null;
}
//仓库中没有产品,则消费线程等待
while((front==rear) && consumerRunning){
wait();
consumerRunning=((Consumer)currentThread).isRunning();
} if(!consumerRunning){
return null;
} Product product=products[front];
front=(front+1+CAPACITY) % CAPACITY;
System.out.println("Concumer"+Thread.currentThread().getName());
System.out.println("剩余产品"+(rear+CAPACITY-front)%CAPACITY);
notify();
return product;
}
} public void storageProduct(Product product) throws InterruptedException {
synchronized(this){
boolean producerRunning=true;
Thread currentThread=Thread.currentThread();
if(currentThread instanceof Producer){
producerRunning=((Producer)currentThread).isRunning();
}else{
return;
}
//仓库中没有产品,则消费线程等待
while(((rear+1)%CAPACITY==front) && producerRunning){
wait();
producerRunning=((Producer)currentThread).isRunning();
} if(!producerRunning){
return;
} products[rear]=product;
rear=(rear+1)%CAPACITY;
System.out.println("Producer"+Thread.currentThread().getName());
System.out.println("剩余产品"+(rear+CAPACITY-front)%CAPACITY);
notify();
}
} }

5、两个同时启动的线程,通常优先级高的线程会先运行。
6、守护线程(Daemon线程)
Thread的setDaemon方法设置线程是否为守护线程。必须在调用start之前调用该方法,否则无效。
只有当程序中所有的非守护线程都结束时,守护线程才会无条件地立即结束,并且不会调用finally中的语句。
7、线程池
将执行某一类任务的线程放在线程池中,有任务要执行时,从池中取出一个空闲线程来处理任务,处理结束后,再将线程池放入池中。
自定义线程池
(1)任务接口

public interface Task {
public void perform() throws Exception;
}

(2)自定义任务类

public class MyTask implements Task {
private int taskId=0; public MyTask(int id) {
this.taskId=id;
} @Override
public void perform() throws Exception {
System.out.println("task "+taskId+" begin");
try{
Thread.sleep(1000);
}catch(InterruptedException e){
}
System.out.println("task "+taskId+" end");
}
}

(3)线程池

public class MyThreadPool extends ThreadGroup{
private boolean isAlive;
private LinkedList taskQueue;
private int threadId;
private static int threadPoolId; public MyThreadPool(int numThreads) {
super("ThreadPool-"+(threadPoolId++));
super.setDaemon(true); //线程池中所有线程被销毁时,线程池自动销毁
this.isAlive=true;
this.taskQueue=new LinkedList();
for(int i=0;i<numThreads;i++){
new PooledThread().start();
}
}
//内部类,工作线程
private class PooledThread extends Thread{ public PooledThread() {
super(MyThreadPool.this,"PooledThread-"+(threadId++));
} @Override
public void run() {
while(!isInterrupted()){
Task task=null;
try{
task=getTask();
}catch(InterruptedException e){ }
if(task==null){
return;
}
try{
task.perform();
}catch(Throwable t){
uncaughtException(this,t);
}
}
}
} protected synchronized Task getTask() throws InterruptedException{
if(!this.isAlive){
return null;
}
while(this.taskQueue.size()==0){
wait();
}
return (Task)this.taskQueue.removeFirst();
} public synchronized void performTask(Task task){
if(!this.isAlive){
throw new IllegalStateException();
}
if(task!=null){
this.taskQueue.add(task);
notify();
}
}
//关闭线程池,所有线程停止,不再执行任务
public synchronized void close(){
if(isAlive){
this.isAlive=false;
this.taskQueue.clear();
this.interrupt();
}
} //关闭线程池,等待所有任务执行完成
public void join(){
synchronized(this){
this.isAlive=false;
this.notifyAll();
} Thread[] threads=new Thread[this.activeCount()];
//将线程池中活动线程拷贝到新的线程组中
int count=this.enumerate(threads);
for(int i=0;i<count;i++){
try{
threads[i].join();
}catch(InterruptedException e){
}
}
}
}

8、当线程进入对象的synchronized代码块时,占有了该资源,直到退出该代码块或者调用wait方法,才会释放该资源,在此期间,其他线程将不能进入该代码块。synchronized尝试占有对象资源,如果不能占有,将一直等待。
线程相互占有对方等待的资源且都不主动释放所占有的资源时,将发生线程死锁。
9、定时器的使用
(1)实现一个继承TimerTask抽象类的自定义类MyTimerTask
(2)结合Timer实现定时执行任务的功能

Timer timer=new Timer();
TimerTask myTask1=new MyTimerTask();
timer.schedule(myTask1,200,300);//200ms后执行myTask1,之后每隔300ms执行一次myTask1

(3)中止定时任务

timer.cancle();

六、反射
1、反射(Reflection)允许Java程序对自身进行检查,并能直接操作程序的内部属性。
2、instanceof 在运行时判断对象的类型
3、java.lang.reflect包实现了java的反射机制。

七、网络编程
1、URL通信
2、Socket通信
3、UDP通信