JAVA笔记

本文深入探讨了Java中String比较的最佳实践、实时读写文件的方法、使用ScheduledExecutorService进行定时任务的高级技巧,以及Swing界面设计中的一些注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

String

==与equals

  看了一部分讲解,个人理解,应该时刻记得String是一个类,并不是int等基本类型。由于类是用new在堆上创建对象,且对象的地址存在于栈中,而int等基本类型是在栈上创建。所以用“==”比较的是栈内的值,也就是说用“==”比较基本类型时,比较的是基本类型的取值,而用“==”比较类的对象时,比较的是该对象的地址。当使用“equals”比较时,比较的是堆中的取值是否相同。因此String等类在比较对象的取值时应该用equals。

实时读写文件

写properties

不使用Spring 的 Environment

  有一次在编码的时候,使用的是Spring 的Environment类,导致无法实时读取,可能是由于Environment类只是在程序启动的时候将文件读入内存,之后不再反复读取的原因。只要正常使用Properties类,在每次读取时重新打开输入流,读取之后关闭输入流即可做到实时读取。

SafeProperties properties = new SafeProperties();
        try {

            InputStream inputStream = new BufferedInputStream(new FileInputStream(propertiesFilePath));
            properties.load(inputStream);
            inputStream.close();
        } catch (Exception exception) {
            exception.printStackTrace();
        }

只读写内存中的,不写入实体文件

  参考http://bbs.youkuaiyun.com/topics/392066071,使用如下方式:

        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("BaseConfig.properties");

        OutputStream outputStream = new FileOutputStream(new File(this.getClass().getClassLoader().getResource("BaseConfig.properties").getFile()));

  此时加载的是class编译后的执行路径,可以做到写完数据后,下次读的时候读取到的是新数据。但从始至终,即使程序退出,也不会将数据写入到实际的文件中。例子:

public class ConfigUtil {
    private static ConfigUtil instance;
    private static Properties properties = null;
    private ConfigUtil() {
        properties = new Properties();

        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("BaseConfig.properties");
        try {
            properties.load(inputStream);
        } catch (IOException ex) {
            Logger.getLogger(ConfigUtil.class.getName()).log(Level.SEVERE, null, ex);
        }finally{
            if (inputStream!=null) {
                try {
                    inputStream.close();
                } catch (IOException ex) {
                    Logger.getLogger(ConfigUtil.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

    }

    public static ConfigUtil getInstance() {
        if (instance == null) {
            instance = new ConfigUtil();
        }
        return instance;
    }

    public String getValueByKey(String key) {

        return (String) properties.get(key) == null ? "空" : (String) properties.get(key);
    }
    public void setValueByKey(String key ,String value) throws FileNotFoundException, IOException {
        properties.setProperty(key, value);

        OutputStream outputStream = new FileOutputStream(new File(this.getClass().getClassLoader().getResource("BaseConfig.properties").getFile()));
        properties.store(outputStream, "");
        outputStream.close();


    }
    public static void main(String[] a) throws FileNotFoundException, IOException {
       ConfigUtil configTool = ConfigUtil.getInstance();
       System.out.println(configTool.getValueByKey("test"));
       configTool.setValueByKey("test", "33");
       System.out.println(configTool.getValueByKey("test"));
       configTool.setValueByKey("test", "44");
       System.out.println(configTool.getValueByKey("test"));
       configTool.setValueByKey("test", "55");
       System.out.println(configTool.getValueByKey("test"));

    }
}

使用线程读入,该方法没有做到实时

  使用新的线程读入properties文件,参考http://java-my-life.iteye.com/blog/1313706

            InputStream in = new BufferedInputStream(new FileInputStream(Thread  
                    .currentThread().getContextClassLoader().getResource(  
                            "test.properties").getPath()));              

  例子

import java.io.BufferedInputStream;  
import java.io.FileInputStream;  
import java.io.InputStream;  
import java.util.Properties;  


public class Test extends Thread{  
    public void run()  
    {  
        while(true){  
            try {  
                this.sleep(1000);  
                readProperties();  
            } catch (InterruptedException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
        }  
    }  
    private static void readProperties()  
    {  
        Properties p = new Properties();  
        try {  
            InputStream in = new BufferedInputStream(new FileInputStream(Thread  
                    .currentThread().getContextClassLoader().getResource(  
                            "test.properties").getPath()));  
            p.load(in);  
            in.close();  
            String name = p.getProperty("name");  
            String id = p.getProperty("id");  
            System.out.println("id=" + id + "\t name=" + name);  
        } catch (Exception e1) {  
            e1.printStackTrace();  
        }  
    }  
    public static void main(String[]args)  
    {  
        new Test().start();  
    }  
}  

读properties

防止乱码

  为了防止乱码,load时可以使用InputStreamReader,然后设置charsetName为utf-8。但是使用这种方式写入时,无论是否使用SafeProperties等自定义的类,都无法保留properties文件中的注释及空行。所以尽量读写分离。

            Properties properties = new SafeProperties();
            InputStream inputStream = new BufferedInputStream(new FileInputStream(propertiesFilePath));
            properties.load(new InputStreamReader(inputStream, "utf-8"));
            inputStream.close();

读取JAR包内的文件

获取流

  被读取的文档路径要设置成以JAR包根目录为基础的路径,如下图,environment.properties文件在JAR包根目录下的properties文件夹内,因此路径要写成”properties/environment.properties”
这里写图片描述

    InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("properties/environment.properties");
    properties.load(inputStream);
    inputStream.close();

同步/互斥

Semaphore

模拟mutex

  在定义Semaphore的时候,令可用资源数量=1,即可模拟mutex。

定时任务

ScheduledExecutorService

启动

  使用ScheduledExecutorService的好处有很多,参考说明,相比于Timer具体有三处优势,1是支持多线程多任务,2是对于每个线程异常的单独处理,3是Timer执行周期任务时依赖系统时间,当系统时间变化时,会影响执行上的变化,ScheduledExecutorService基于时间的延迟,不会由于系统时间的改变发生执行变化。使用方法参考例子

package com.effective.common.concurrent.execute;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Schedule {

    private static DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
    private static DateFormat dayFormat = new SimpleDateFormat("yy-MM-dd");

    private static ScheduledExecutorService excutor = Executors.newSingleThreadScheduledExecutor();

    /**
     * 按指定频率周期执行某个任务 <br>
     * 初始化延迟0ms开始执行,每隔5ms重新执行一次任务。
     */
    public void fixedRate(){
        excutor.scheduleAtFixedRate(new EchoServer(), //执行线程
                                    0,  //初始化延迟
                                    5000, //两次开始的执行的最小时间间隔
                                    TimeUnit.MILLISECONDS //计时单位
                                    );
    }

    /**
     * 
     */
    public void fixDelay(){
        excutor.scheduleWithFixedDelay(new EchoServer(),//执行线程 
                0, //初始化延迟
                5000, //前一次执行结束到下一次执行开始的间隔时间
                TimeUnit.MILLISECONDS);
    }

    /**
     * 每天晚上8点执行一次
     */
    public void dayOfDelay(String time){
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);  
        long oneDay = 24 * 60 * 60 * 1000;  
        long initDelay  = getTimeMillis("20:00:00") - System.currentTimeMillis();  
        initDelay = initDelay > 0 ? initDelay : oneDay + initDelay;  
        executor.scheduleAtFixedRate(  
                new EchoServer(),  
                initDelay,  
                oneDay,  
                TimeUnit.MILLISECONDS); 
    }


    /**
     * 获取给定时间对应的毫秒数
     * @param string "HH:mm:ss"
     * @return
     */
    private static long getTimeMillis(String time) {        
        try {
            Date currentDate = dateFormat.parse(dayFormat.format(new Date()) + " " +time);
            return currentDate.getTime() ;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0;
    }

    public static void main(String[] args){

        Schedule schedule = new Schedule();
        schedule.fixedRate();
        schedule.fixDelay();

    }

}

取消定时任务

  使用下述语句可以取消已经建立的定时任务,但是我仅仅在线程未执行或执行结束的时候用过,执行shutdown后该线程不再定时启动。若该任务线程正在执行,不知道是否可以强行终止。

    scheduledExecutorService.shutdown();

  当使用newSingleThreadScheduledExecutor()创建时,可能是由于创建的是单独的一个线程,所以在线程创建之后,线程池中已经空了。在shutdown之后,当再次启动定时任务时,会由于线程池空了而报错,异常信息:

java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask@6386eba1 rejected from java.util.concurrent.ScheduledThreadPoolExecutor@5e5a567f[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]

  因此在使用newSingleThreadScheduledExecutor()且执行了shutdown操作后,若是想再次启动定时任务,需要重新通过newSingleThreadScheduledExecutor()获取对象。

    scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

Swing

多线程中不显示界面

  下图为一个创建界面的类,当在绘制swing界面的类内部,直接在函数中使用sleep或semaphore的acquire函数时,会导致界面显示异常,仅仅剩下一个frame,无法显示加载的pannel。
这里写图片描述      这里写图片描述
  因此若需要在多个线程所控制的界面之间切换,要在线程内的run函数中写sleep,acquire等函数,这样才能正常显示。至于导致这一问题的原因,还不清楚,需要再查资料看一看,怀疑是因为sleep等导致阻塞,使得pannel无法显示。

设置图标

设置程序显示图标

  为JFrame添加图标,由于java只识别jpg、png等,不能识别ico,因此不能使用ico图片。

            Image image = Toolkit.getDefaultToolkit().getImage(iconPath + "\\mainForm.png");
            frame.setIconImage(image);

窗口按钮

不关闭窗口

  当点击窗口右上角的红叉时,不关闭窗口,并执行重写的windowClosing操作。

        frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                JOptionPane.showMessageDialog(null, "请等待数据处理结束!");
            }
        });
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值