java实用技巧

1、深度复制java对象

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(orders1);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
List<Order> orders =  (List<Order>)ois.readObject();

首先Order对象需要实现serializable接口,然后通过对象输出流,把序列化后的对象存入内存中,然后在用对象输入流从内存中反序列化读取对象


2、遍历list的同时删除list中的元素

 for (int i = orders.size() - 1; i >= 0; i--) {
            Order order = orders.get(i);
            List<Product> products = order.getProducts();
            for (int j = products.size() - 1; j >= 0; j--) {
                Product product = products.get(j);
                if (!product.getSelected()) {
                    products.remove(j);
                }
            }
            if (0 == products.size()) {
                orders.remove(i);
            }
 }

由于遍历的同时删除list中的元素的话list的size会变化,所以必须反序的遍历才能保证真确性

3、把double类型,正确的输出成正确的金额(保留2位小数)

new BigDecimal(54d).setScale(2, BigDecimal.ROUND_HALF_UP).toString()

4、如何使得主线等待所有子线程执行完毕后,主线程才能继续执行,子线程可以不只一个

思路:主线程所在的类中,应该有一个成员变量记录所有子线程的数量,比如int count=3,count代表子线程的数量,生成count属性的get、set方法,2个方法都需要加上synchronized。在写一个minus()方法,此方法也需要加上synchronized关键子,作用是调用此方法count就减去1。主线程中需要有一个判断,判断是否能继续执行下去,只有当count==0是才能继续执行。子线程执行完后需要调用minus方法。

5、有一张底图,需要在底图上写上一些文字,比如验证码


BufferedImage image = ImageIO.read(new File(picURL));
int imageWidth = image.getWidth();
int imageHight = image.getHeight();
Graphics g = image.getGraphics();
g.setColor(new Color(255,255,255));
g.fillRect(0, 0,150,50);
g.setColor(new Color(0,0,0));
g.setFont(new Font(null,0,50));
g.drawString(validateCode,6,50); 
g.dispose();
ImageIO.write(image,"jpg", response.getOutputStream());

首先,读取图片文件生成BufferedImage,然后就可以进行一系列的操作

6、java定时任务

 一、延时执行

public class TimeTask {
     public static void main(String[] args){
            Timer timer = new Timer();
            timer.schedule(new Task(), 60 * 1000);
      }
}
timer.schedule()方法中第一个参数是我们需要执行的任务,第二个参数是延迟多少时间后执行,这里是延迟1分钟

public class Task extends TimerTask {
     public void run(){
              System.out.println("定时任务执行");
      }
}

我们的Task必须实现TimerTask的方法run,要执行的任务就在这个run方法里面,这里,我们只让它往控制台打一行字。

二、循环执行
设置定时任务的时候,往往我们需要重复的执行这样任务,每隔一段时间执行一次,而上面的方法是只执行一次的,这样就用到了schedule方法的是另一个重载函数
public void schedule(TimerTask task,long delay,long period)
  前两个参数就不用说什么了,最后一个参数就是间隔的时间,又是个long型的毫秒数(看来java里涉及到时间的,跟这个long是脱不了干系了),比如我们希望上面的任务从第一次执行后,每个一分钟执行一次,第三个参数值赋60 * 1000就ok了。
三、指定执行时间
既然号称是定时任务,我们肯定希望由我们来指定任务指定的时间,显然上面的方法就不中用了,因为我们不知道程序什么时间开始运行,就没办法确定需要延时多少。没关系,schedule四个重载的方法还没用完呢。用下面这个就OK了:
public void schedule(TimerTask task,Date time)
比如,我们希望定时任务2006年7月2日0时0分执行,只要给第二个参数传一个时间设置为2006年7月2日0时0分的Date对象就可以了。
有一种情况是,可能我们的程序启动的时候,已经是2006年7月3日了,这样的话,程序一启动,定时任务就开始执行了。
 
schedule最后一个重载的方法是
public void schedule(TimerTask task,Date firstTime,long period)


7、java对时间的处理

一、格式化时间与设置时间
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
把当前的时间格式化成指定格式,可以用simpleDateFormat这个类,这个类中分装了各种有用的方法
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date day = sdf.parse("2012-10-01 00:00:00");
同样设置时间也可以用simpleDateFormat这个类

Canlendar也可以用来设置时间,代码如下
Calendar ca = Calendar.getInstance();
ca.set(Calendar.YEAR, 2006);
ca.set(Calendar.MONTH, 7);
ca.set(Calendar.DAY_OF_MONTH, 1);
ca.set(Calendar.HOUR_OF_DAY, 14);
ca.set(Calendar.MINUTE,0);
ca.set(Calendar.SECOND, 0);
Date date = ca.getTime();

如果需要计算昨天的日期,或者后天的日期可以用

ca.add(Calendar.DATE,-1) //昨天
ca.add(Calendar.DATE,1) //后天

二、时间的运算

举个例子,已知两个Date型时间对象,date1、date2,我们需要计算出这两个时间之间相差几个小时,怎么做。
Calendar ca1 = Calendar.getInstance();
Calendar ca2 = Calendar.getInstance();
ca1.setTime(date1);
ca2.setTime(date2);
int distanceHour = ca2.get(Calendar.HOUR_OF_DAY) - ca1.get(Calendar.HOUR_OF_DAY);



8、当文件太大、无法一次性的放入内存读取时,如何读取此文件

内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问。这种解决办法能大大简化修改文件的代码。

fileChannel.map(FileChannel.MapMode mode, long position, long size)
将此通道的文件区域直接映射到内存中。注意,你必须指明,它是从文件的哪个位置开始映射的,映射的范围又有多大;也就是说,它还可以映射一个大文件的某个小片断。


MappedByteBuffer是ByteBuffer的子类,因此它具备了ByteBuffer的所有方法,但新添了force()将缓冲区的内容强制刷新到存储设备中去、load()将存储设备中的数据加载到内存中、isLoaded()位置内存中的数据是否与存储设置上同步。这里只简单地演示了一下put()和get()方法,除此之外,你还可以使用asCharBuffer( )之类的方法得到相应基本类型数据的缓冲视图后,可以方便的读写基本类型数据

public class LargeMappedFiles {  
    static int length = 0x8000000; // 128 Mb  
  
    public static void main(String[] args) throws Exception {  
        // 为了以可读可写的方式打开文件,这里使用RandomAccessFile来创建文件。  
        FileChannel fc = new RandomAccessFile("test.dat", "rw").getChannel();  
        //注意,文件通道的可读可写要建立在文件流本身可读写的基础之上  
        MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, 0, length);  
        //写128M的内容  
        for (int i = 0; i < length; i++) {  
            out.put((byte) 'x');  
        }  
        System.out.println("Finished writing");  
        //读取文件中间6个字节内容  
        for (int i = length / 2; i < length / 2 + 6; i++) {  
            System.out.print((char) out.get(i));  
        }  
        fc.close();  
    }  
}  

该程序创建了一个128Mb的文件,如果一次性读到内存可能导致内存溢出,但这里访问好像只是一瞬间的事,这是因为,真正调入内存的只是其中的一小部分,其余部分则被放在交换文件上。这样你就可以很方便地修改超大型的文件了(最大可以到2 GB)。注意,Java是调用操作系统的"文件映射机制"来提升性能的。

9、多个线程同时写入一个文件,利用RandomAccessFile

/** 
 * 测试利用多线程进行文件的写操作 
 */  
public class Test {  
  
    public static void main(String[] args) throws Exception {  
        // 预分配文件所占的磁盘空间,磁盘中会创建一个指定大小的文件  
        RandomAccessFile raf = new RandomAccessFile("D://abc.txt", "rw");  
        raf.setLength(1024*1024); // 预分配 1M 的文件空间  
        raf.close();  
          
        // 所要写入的文件内容  
        String s1 = "第一个字符串";  
        String s2 = "第二个字符串";  
        String s3 = "第三个字符串";  
        String s4 = "第四个字符串";  
        String s5 = "第五个字符串";  
          
        // 利用多线程同时写入一个文件  
        new FileWriteThread(1024*1,s1.getBytes()).start(); // 从文件的1024字节之后开始写入数据  
        new FileWriteThread(1024*2,s2.getBytes()).start(); // 从文件的2048字节之后开始写入数据  
        new FileWriteThread(1024*3,s3.getBytes()).start(); // 从文件的3072字节之后开始写入数据  
        new FileWriteThread(1024*4,s4.getBytes()).start(); // 从文件的4096字节之后开始写入数据  
        new FileWriteThread(1024*5,s5.getBytes()).start(); // 从文件的5120字节之后开始写入数据  
    }  
      
    // 利用线程在文件的指定位置写入指定数据  
    static class FileWriteThread extends Thread{  
        private int skip;  
        private byte[] content;  
          
        public FileWriteThread(int skip,byte[] content){  
            this.skip = skip;  
            this.content = content;  
        }  
          
        public void run(){  
            RandomAccessFile raf = null;  
            try {  
                raf = new RandomAccessFile("D://abc.txt", "rw");  
                raf.seek(skip);  
                raf.write(content);  
            } catch (FileNotFoundException e) {  
                e.printStackTrace();  
            } catch (IOException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            } finally {  
                try {  
                    raf.close();  
                } catch (Exception e) {  
                }  
            }  
        }  
    }  
  
}  

10、使用jdbc批处理提高sql语句的执行效率

下面是一个简单的java.sql.Statement的例子:
Statement stmt = conn.createStatement();
stmt.insert("DELETE FROM Users");
stmt.insert("INSERT INTO Users VALUES('rod', 37, 'circle')");
stmt.insert("INSERT INTO Users VALUES('jane', 33, 'triangle')");
stmt.insert("INSERT INTO Users VALUES('freddy', 29, 'square')");
int[] counts = stmt.executeBatch();

使用PreparedStatement会稍有不同。它只能处理一段SQL语句,但可以带很多参数。下面的是使用

PreparedStatement重写的上面的例子:

PreparedStatement stmt = conn.prepareStatement( "INSERT INTO Users VALUES(?,?,?)" );
User[ ] users = ...;
for(int i=0; i<users.length; i++)
{
stmt.setInt(1, users[i].getName());
stmt.setInt(2, users[i].getAge());
stmt.setInt(3, users[i].getShape());
stmt.addBatch( );
}
int[ ] counts = stmt.executeBatch();

这是处理那些不知道具体执行次数的SQL代码的一个好方法。没有批处理,如果要添加50个用户,其性能可

能受到影响。如果谁写了一段添加10000个用户的脚本,其运行速度就难以忍受。增加批处理将有助于提升

性能,在后一种情况里,甚至可以改善代码的可读性。










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值