前言:本文『很傻很天真』,任何稍有Java编程经验的都不用看了。
(1)Java文件编译得到class文件,jar包是若干class文件(以及其他一些文件)的集合,如果要在命令行运行jar包中的一个class文件(相当于一个Java程序),可以这样做:
java -cp /root/software/tmp/XXX.jar:/root/software/tmp/lib/* com.abc.calculate.MyClass --date 20101101
其中,-cp 表示指定classpath,后面需要以分号(:)分隔的方式将所有需要用到的依赖jar包添加进来,此处添加了 /root/software/tmp/XXX.jar 包以及 /root/software/tmp/lib/ 目录下的所有jar包。
com.abc.calculate.MyClass 是要运行的jar包 XXX.jar 中的一个class文件,这么长的名字是它在jar包中的路径全名。
--date是传给 MyClass 程序命令行参数。还可以带更多的参数,要看你在Java程序中是如何写的代码。
(2)import static的含义
类似于
import static com.abc.calculate.MyClass.*;
这样的语句,意思是导入类中的静态方法和静态变量,从而可以在导入的文件中,可以直接使用静态方法或静态变量,不需要再以 类名.静态方法名 或 类名.静态变量名 的方式来调用了,从而使得代码很简洁。
(3)java.lang.ClassNotFoundException: com.mysql.jdbc.Driver 错误
这是由于找不到连接MySQL数据库的JDBC驱动。这个驱动是一个jar包,例如 mysql-connector-java-5.1.17-bin.jar 。你需要在classpath中添加这个文件,或者在运行你的Java程序时,用java -cp 临时指定这个jar文件的路径:
java -cp /home/mydir/mysql-connector-java-5.1.17-bin.jar your_program_name
(4)在IntelliJ IDEA中用快捷鍵生成main函数
在IntelliJ IDEA这个Java开发的IDE中,要输出一个标准形式的main函数简直方便到不行,完全不用你输入任何内容:在要插入main函数的地方按Ctrl+J快捷键,然后按p键,就会看到一个包含“psvm”等选项的下拉菜单,菜单右边有每一项的解释,其中“psvm”对应的解释是“main() method declaration”,因此,我们直接回车,即选择了“psvm” 这一项,然后main函数就直接生成了:
public static void main(String[] args) { }
便捷得让人心欢喜。
文章来源:http://www.codelast.com/
(5)由 javac XXX.java 命令编译得到 XXX.class 文件,但是在执行此Java程序的时候,是执行 java XXX 而不是 java XXX.class !注意不要傻傻地带上“.class”,否则一定会得到一大堆错误,例如“Exception in thread "main" java.lang.NoClassDefFoundError”之类。
(6)一个类实现了接口 public interface Iterable<T> 之后,该类的对象就可以成为 foreach 语句的目标。
(7)如果你执行程序时得到类似于以下错误:
Exception in thread "main" java.lang.NoClassDefFoundError:
Caused by: java.lang.ClassNotFoundException:
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
Could not find the main class: . Program will exit.
那么,这些可能是根本就无关你程序问题的错误。你可以试着执行一下命令:
java ""
会发现也会输出以上错误(双引号中间什么也没有,即一个空字符串)。
这说明是你要执行的程序找不到这些包造成的。请检查你的classpath,确认其正确;另外还要检查你执行命令的当前用户,是不是正确的用户,因为不同的用户会配置不同的环境变量,有可能导致找不到需要的jar包,或者根本没有权限去读取某些jar包!
(8)IntelliJ中自动生成JUnit单元测试代码框架的插件:JunitGenerator 的使用方法
①假设你是在Windows下(Linux也类似),需要在环境变量中的Path里添加上junit.jar文件的路径,例如d:\ProgramFiles\IntelliJ\lib\junit.jar
由于IntelliJ已经自带了一个junit.jar,所以你直接设置成它带的那个文件的路径就可以了。
②下载IntelliJ的JunitGenerator插件,在这里下载。需要下载的是那个zip包:JUnitGeneratorV2.0.zip(如果版本升级了,也下载类似名字的压缩包即可)。
③将zip包里的junitgen.jar文件解压到 IntelliJ安装目录\lib\ 下,将zip包里的resources文件夹解压到C:\Documents and Settings\XXX\.IntelliJIdea10\config\plugins 目录下,其中,XXX是你的登录用户名。至于为什么要这样,你可以先试着不这样做,然后打开IntelliJ,等着它报找不到一堆文件的错误吧。从错误信息就知道怎么解决了。
④打开IntelliJ,在File→Settings→Plugins选项中,可以看到“Installed”列表,即已经安装的插件的列表,确保JunitGeneratorV2.0已经选中,然后重启IntelliJ即可。
⑤在需要生成单元测试代码的类中,按快捷键Alt+Insert,在弹出的菜单中选择“JUnit Test”,即可生成单元测试代码框架,搞定!
文章来源:http://www.codelast.com/
(9)Java中对简单数据类型(例如int,float),在作为函数参数使用时,是传值的,无法作为引用传递,所以如果你的一个函数原型是 public void func(int a, float b),则你传入的a、b值即使在函数func中被更改了,也无法反映到函数外部。如果你习惯了C++的传递引用的方式,那么你在Java中找不到一样的方式,这时,你可以把简单数据数据当作数组来传递,或者把它们封装成一个类来传递。
当作数组传递的例子:
public void func(int[] a, float[] b) { //...... }
这时,你可以在在func中更改a[0],a[1],a[2]……的值,在外部取出来的值就跟着变了。
(10)如何对一个map中的各元素,按照 value 的值从大到小排序?
假设你有一个TreeMap<Integer, Double>对象,里面有5个元素:
(3, 1.3),(4, 2.7),(16, 6.5),(1, 0.5),(9, 0.8)
我们知道,把一对(key, value)放进TreeMap中时,TreeMap会把它们按key自动排序的,例如在这个例子中,你把上面的5个(key, value)对放进了TreeMap之后,你再把它们用遍历entrySet的方式输出,你会发现key的输出顺序为1,3,4,9,16。
现在我想把它们排序成:
(16, 6.5),(4, 2.7),(3, 1.3),(9, 0.8),(1, 0.5)
即:按value值从大到小排序,怎么做呢?
有人会说,把(key, value)对倒过来,按(value, key)的形式保存到另一个TreeMap中,然后再把得到的TreeMap逆序输出,就得到了正确的结果了。在本例中,这样做是可行的,但是,由于TreeMap的key是不能重复的,因此,如果我们在原始的TreeMap中有两个相同的value,则这样做就不行了,因为把(key, value)倒过来之后会出现两个相同的key',保存到新的TreeMap中之后就会丢失一组数据。
那么,还可以怎么办呢?可以借助ArrayList,用Collections.sort()方法来对ArrayList排序,从而实现最终的效果。
假设我们需要排序的TreeMap<Integer, Double>对象名为 tm,其中已经有上面所说的5组(key, value)对了,然后:
// 将TreeMap中的元素放到ArrayList中
ArrayList<Map.Entry<Integer, Double>> tmList = new ArrayList<Map.Entry<Integer, Double>>(tm.entrySet());
// 利用Collections.sort方法排序
Collections.sort(tmList, new Comparator<Map.Entry<Integer, Double>>() {
@Override
public int compare(Map.Entry<Integer, Double> o1, Map.Entry<Integer, Double> o2) {
return o2.getValue().compareTo(o1.getValue());
}
});
// 输出排序后的数据
for (Map.Entry<Integer, Double> entry : tmList) {
System.out.println(String.format("Key : %d, Value : %f", entry.getKey(), entry.getValue()));
}
可见,在上面的代码中,你需要创建一个Comparator对象,并把它作为参数传递到Collections.sort()函数中,在这个Comparator对象中,你需要重载对两个对象进行大小比较的compare()方法。
如果你使用的是Java8或以上版本,那么还有更简洁的做法:
Map<Integer, Double> sortedMapReverseOrder = tm.entrySet().
stream().
sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).
collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
然后遍历 sortedMapReverseOrder 就可以输出按原map对象的value降序排列的值。但要注意,sortedMapReverseOrder 不再是一个TreeMap。
文章来源:http://www.codelast.com/
(12)批量向MySQL数据库INSERT数据时,可以用JDBC的batch insert来插入,这样效率上会提高一些。如果你要将所有待插入的数据用 VALUES (a, b, c), (d, e, f), (g, h, i) 这样的方式拼装成1条SQL语句,再插入数据库的话,不要忘了,SQL语句长度是有限制的,你无法拼接一个极长的语句并执行,而batch insert甚至可以将20万条记录一起批量插入(网上的某些文章说的),所以,在一次插入很多数据时,你也不得不用batch insert。
文章来源:http://www.codelast.com/
(13)如果要开发Android应用程序,就必须安装Android SDK,在Windows下安装Android SDK的时候可能会有一直怪异的现象:明明已经安装过了JDK的,但是Android SDK的安装程序装报告说找不到JDK,这个时候,你只要在安装向导中点一下后退按钮返回上一界面,再点击前进按钮回来,就发现不再提示找不到JDK了,雷人啊。另外,安装好之后启动SDK Manager时也有可能会提示“Java not found in your path”,真让人不解。要解决这个问题,你可以试试把JDK安装路径下的java.exe的路径添加到你Windows的环境变量中的“Path”中,例如你的java.exe是在 D:\Java\jdk1.6.0_26\bin 目录下,那么你就把这个路径添加到Path中就可以了。
(14)IntelliJ如果提示“@Override”语法错误(波浪线),你可以在IntelliJ的“File→Project Structure”中设置:在“Project Language Level”中选择“6.0 - @Override in interfaces”,并重新加载工程即可。
(15)Ant中的 ** 匹配任意数量的目录,例如,模式 **/*.java 将匹配当前目录结构下的所有 Java 文件。
(16)在Linux下装ant
到这里去下载ant的tar.gz版本,解压出来得到 apache-ant-1.8.2 目录,放置到 /usr/local/ 目录下,然后做一个软链接:
ln -s /usr/local/apache-ant-1.8.2 /usr/local/ant
再将此链接添加到 /etc/profile 中:
ANT_HOME=/usr/local/ant export PATH=$JAVA_HOME/bin:$ANT_HOME/bin:$PATH
如果不想重启当前session就使此设置生效的话,需要手工加载一下 /etc/profile :
source /etc/profile
现在,你应该可以在命令行运行ant命令了。安装成功。 文章来源:http://www.codelast.com/
(17)Java设计模式之Factory
请看这个链接。
(18)抽象类(abstract class)和接口(interface)的区别
请看这个链接。引用其中的几段话:
abstract class可以有自己的数据成员,也可以有非abstract的成员方法,而interface只能够有静态的不能被修改的数据成员(也就是必须是static final 的,不过在interface中一般不定义数据成员),所有的成员方法都是abstract的。从某种意义上说,interface是一种特殊形式的abstract class。
abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系(因为Java不支持多继承 -- 转注)。但是,一个类却可以实现多个interface。也许,这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。其次,在abstract class的定义中,我们可以赋予方法的默认行为。但是在interface的定义中,方法却不能拥有默认行为,为了绕过这个限制,必须使用委托,但是这会增加一些复杂性,有时会造成很大的麻烦。
abstract class在Java语言中体现了一种继承关系,要想使得 继承关系合理,父类和派生类之间必须存在"is-a"关系,即父类和派生类在概念本质上应该是相同的。对于interface来说则不然,并不要求interface的实现者和interface定义在概念本质上是一致的, 仅仅是实现了interface定义的契约而已。
1.abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。2.在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的。3.abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系。4.实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。5.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。6.抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。7.接口中的方法默认都是 public,abstract 类型的。
(19)在Java中执行Linux shell命令
类似于C中的system()函数:
NAMEsystem - execute a shell commandSYNOPSIS#include <stdlib.h>int system(const char *command);
Runtime runTime = Runtime.getRuntime(); String cmd = String.format("hadoop fs -put %s %s", fileLocal, fileOnHDFS); runTime.exec(cmd);
这样就可以执行字符串 cmd 中的shell命令。
(20)时间库Joda Time,一个用来替换JDK的时间库的Java库
其主页:http://joda-time.sourceforge.net/
Joda Time之所以被创造出来,是为了从根本上改变Java中的日期、时间的处理方式。JDK中的Date和Calendar类被设计得非常糟糕,并且有很多bug,因此,人们才创造了Joda Time这个Java库,来彻底替代它们。
(21)如何得到一个时间戳对应的时间中的hour(小时)
假设有时间戳(毫秒数)1212680215000,它对应的时间是“2008-06-05 23:36:55”,如果我们要取出其中的小时数,即 23,该怎么做?
对,你可以用Date类,向它的构造函数传入这个时间戳,就可以得到一个对应这个时间的对象,然后可以用Date类的getHours()方法来获取小时。但是你会发现,JDK文档表示,该方法早已过时了,那么,如果我要用一个“不过时”的方法来实现,应该怎么写?
方法如下:
Calendar calendar = GregorianCalendar.getInstance(); calendar.setTimeInMillis(timestamp); int hour = calendar.get(Calendar.HOUR_OF_DAY);
这种方法非常麻烦。你需要先构造一个Calendar类的对象,然后再设置其时间(这里的timestamp即为上面所说的时间戳),然后再用get方法获取小时。这里的Calendar.HOUR)OF_DAY是指定了获取24小时制的小时。
文章来源:http://www.codelast.com/
对刚接触Java的人来说,用Date类的getHours方法来获取小时是让人感觉非常直观的做法,但是它居然“过时”了,并且,如你所见,用上面的Calendar类来达到同样的效果,是多么地绕弯子啊,并且给人感觉非常脑残,所以,这就是Joda Time对JDK的日期、时间库批评有加的原因了。对Joda Time的详细介绍,请看其主页。在这里,也只能对你说,能用Joda Time的话,就尽量抛弃JDK的日期、时间库吧。
(22)JAVA中的静态代码块(转载)
public class Driver extends NonRegisteringDriver implements java.sql.Driver { …… static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } } …… }
初始化类中属性是静态代码块的常用用途,但只能使用一次。
(23)org.apache.commons.io.FileUtils的deleteQuietly()方法与JDK的delete()方法的区别
同样是删除 文件或目录 的方法,前者与后者的区别是:前者不要求被删除目录为空(里面可以有东西),删不掉时也不会抛出异常。
(24)类(class)的访问权限(转载)
private和protected也可以作为class的修饰符,但只是当此class是一个内部类的时候可以,对最外层的class来说,它只能有public修饰符或没有修饰符。
(25)方法抛出NullPointerException异常不需要声明
NullPointerException是不需要在方法声明中写的。
文章来源:http://www.codelast.com/
(26)重写父类方法的@Override
一个类方法的上方有一行 @Override 标记的话,表明此方法是重写了父类的方法,如果没有,这个方法会被认为是本类自己的方法(而不是重写父类的),因此,如果你的方法名写错了(例如少写了一个字母),并且你是想重写父类的方法的话,加上@Override可以让编译器在编译的时候就检查出错误,例如:
(27)运行一个使用log4j的Java程序时,如何在命令行指定使用特定的log4j配置文件
如果你的Java程序使用了log4j来记录日志,那么,将log4j的配置文件打进jar包中会导致无法方便地修改log4j配置(要重新打包比较麻烦),所以,你可以在调用此Java程序的脚本中使用如下方法来使用指定的log4j配置文件:
DIR=/example/code java -Dlog4j.configuration=file://$DIR/config/my_log4j.properties \ com.codelast.LogTest
上面的代码使得:运行 com.codelast.LogTest 程序时,使用 /example/code/config/my_log4j.properties 作为log4j的配置文件。
(28)打印出java.util.Date对象的日期
假设你有一个Date对象,它是由一个字符串“20120228”解析来的,现在要以“2012-02-28”的形式打印出其日期,则:
String str = "20120228"; date = DateUtils.parseDate(str, new String[]{"yyyyMMdd"}); String res = new SimpleDateFormat("yyyy-MM-dd").format(date);
就可以做到。
再举个例子,打印出昨天的日期:
String yesterday = new SimpleDateFormat("yyyy-MM-dd").format(DateUtils.addDays(new Date(), -1));
(29)Spring中的若干标签的含义
①constructor-arg:构造函数的参数。
例如:
<bean id="abc" class="com.codelast.MyClass" > <constructor-arg value="33" index="0" /> <constructor-arg value="google" index="1" /> </bean>
这段XML说明:类MyClass的构造函数应该包含两个参数,在生成MyClass对象的时候,第1个参数(index="0")的值被赋为33,第2个参数(index="1")的值被赋为“google”。
其构造函数类似于:
public MyClass(int userId, String companyName) { //TODO: }
文章来源:http://www.codelast.com/
②property:属性,对应到类中的setter方法。
例如:
<bean id="abc" class="com.codelast.MyClass" > <property name="companyName" value="google" /> </bean>
这段XML说明:类MyClass应该有一个叫做 setCompanyName 的方法(对应于“companyName”这个属性),类似于:
public void setCompanyName(String companyName) { //TODO: }
构造MyClass对象的时候,就会自动调用 setCompanyName 方法,把“google”这个值传进去。
③构造函数,set方法,init-method的执行顺序
按照这篇文章的说法,以上三者的执行顺序为:构造函数→set方法→init-method。因此,在init-method中是可以取到配置文件通过set方法设置的参数值的。
(30)不可修改的Collection
假设你有一个Collection:
Collection<String> strCol = new ArrayList<String>;
如果要在一个方法中,返回这个Collection,但是又不想返回值被外部修改,那么就要返回一个不可修改的Collection:
Collections.unmodifiableCollection(strCol);
注意是“Collections”,别看错了!
(31)IntelliJ缓存文件的清理
IntelliJ这个强大的JAVA IDE非常好用,如果你的系统盘空间紧张,会发现它的缓存文件越来越大的确是个严重的问题,所以我们需要手动清理。如果你是在Windows下使用IntelliJ,那么找到系统盘的这个目录:
C:\Users\登录用户名\.IntelliJIdea10\system
不同的IntelliJ版本对应的目录名是不同的,例如,IntelliJ 11.1对应的目录不是“...\.IntelliJIdea10\...”,而是“...\.IdeaIC11\...”(同理,IntelliJ 12对应的是.IdeaIC12)。你可以把这个system目录删掉(其占用空间可能非常大),再次打开IntelliJ时它会重建。
(32)多线程实现之Runnable接口和Thread类
实现多线程可以 extends Thread类,也可以implements Runnable接口。由于JAVA的单继承特性,第一种方法使得你的类不能再继承第二个类,这在某些情况下是不太好的(可能你一定需要继承自某个类,但是为了实现多线程,就必须要放弃继承它);第二种方法使得你不必影响原有的类层次关系,就可以为你的类添加上多线程功能,并且接口是可以实现多个的,在某些情况下扩展性更佳。
(33)周期性执行某一job的一种方法
如果要周期性执行某一个任务,那么我们首先想到的方法就是:创建一个线程,在里面用while循环配合sleep方法来实现周期性执行。且不论这种方法的好坏,我们有另一种更简单的方法:使用 ScheduledExecutorService 接口。
private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
文章来源:http://www.codelast.com/
设置周期性执行的任务:
executorService.scheduleAtFixedRate(myRunnableClassObject, 0, 2, TimeUnit.MINUTES);
其中,第一个参数是一个实现了Runnable接口的类的对象(此类必须实现run方法),第二、三个参数分别表示任务开始的时间和周期,第四个参数为时间单位。
这样,你就不用自己在一个线程中用while循环来控制周期性任务了,非常方便。
(34)如何生成XML字符串/Java生成XML
如果要把你指定的内容生成一段XML字符串,可以用JDOM这个类库,你需要在你的项目中添加 jdom-2.0.2.jar 这个jar包(名字可能不同,请去官方网站下载最新的jar包)。
示例代码如下:
String content = ""; Element element = new Element("ele"); Document doc = new Document(element); element.addContent(new Element("date").setText("2012-07-11")); element.addContent(new Element("id").setText("78jskfjk4")); ByteArrayOutputStream byteRep = new ByteArrayOutputStream(); Format format = Format.getPrettyFormat(); format.setEncoding("UTF-8"); format.setIndent(" "); XMLOutputter xmlOutputter = new XMLOutputter(format); try { xmlOutputter.output(doc, byteRep); } catch (IOException e) { } content += byteRep.toString(); System.out.printf(content);
另外,上面的代码需要import的JDOM相关类如下:
import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter;
最后输出的XML字符串为:
<?xml version="1.0" encoding="UTF-8"?> <ele> <date>2012-07-11</date> <id>78jskfjk4</id> </ele>
(35)“@Override is not allowed when implementing interface method”错误的解决办法
如果你使用的Java IDE是IntelliJ,并且遇到了这个错误提示,那么可能是项目属性设置不对导致的,试试:
在菜单“File”→“Project Structure”→“Project Language Level”里选择“6.0 - @Override in interfaces”,然后重新打开工程。
(36)用String类的split()方法来分割字符串时,如果分隔符是“|”,应该怎样写
假设有一个字符串s的内容为“a|b|c”(不含引号),那么如果你使用 s.split("|") 来分割字符串,你会发现结果是错误的,那是因为,按split()的定义:
public String[] split(String regex)根据给定正则表达式的匹配拆分此字符串。
左右两边表达式之间 "或" 关系,匹配左边或者右边。
s.split("\\|");
这样就能得到正确的字符串分割结果了。
(37)如何获取当前时间戳(毫秒数)
long timestamp = System.currentTimeMillis();
用currentTimeMillis()这个静态方法来取当前时间戳很方便。
(38)客户端向Thrift service发送数据时,如何指定超时时间
超时时间是在 TSocket 对象的构造函数中设置的:
int timeout = 2; socket = new TSocket(hostAddress, thriftServicePort, timeout); TProtocol protocol = new TCompactProtocol(socket);
而Thrift client对象又需要通过 protocol 来构造,所以,当你调用了client对象的方法来向Thrift service发送数据时,就会以这个超时时间来执行了。
(39)HashMap按key来排序
直接看示例代码:
Map<String, String> m = new HashMap<String, String>(); m.put("c", "12"); m.put("0", "34"); m.put("a", "09"); m.put("e", "10"); m.put("b", "11"); Object[] keys = m.keySet().toArray(); Arrays.sort(keys); for (Object key : keys) { System.out.println(String.format("Key: [%s], value: [%s]", key, m.get(key.toString()))); }
sort()方法的说明如下:
public static void sort(byte[] a)
对指定的 byte 型数组按数字升序进行排序。该排序算法是一个经过调优的快速排序法,改编自 Jon L. Bentley 和 M. Douglas McIlroy 合著的 Engineering a Sort Function", Software-Practice and Experience Vol. 23(11) P. 1249-1265 (November 1993)。此算法在许多数据集上提供 n*log(n) 性能,这导致其他快速排序会降低二次型性能。参数:a - 要排序的数组
以上代码的输出结果为:
Key: [0], value: [34] Key: [a], value: [09] Key: [b], value: [11] Key: [c], value: [12] Key: [e], value: [10]
可见确实按key的升序排序了。
(40)Java读写文本文件时,中文乱码的问题
向文本文件写入中文时乱码,可以这样解决:
File outputFile = new File("/home/abc/out.txt"); OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(outputFile), "UTF-8"); BufferedWriter bw = new BufferedWriter(osw); bw.write("中文" + "\n"); bw.close();
即显式地指定charset为UTF-8。
读取文本文件时,如果文件编码是UTF-8:
File inputFile = new File("data.txt"); InputStreamReader reader; BufferedReader br = null; try { reader = new InputStreamReader(new FileInputStream(inputFile), "UTF-8"); br = new BufferedReader(reader); String line; while ((line = br.readLine()) != null) { //TODO: deal with the string } } catch (Exception e) { //TODO: } finally { if (br != null) { try { br.close(); } catch (IOException e) { //TODO: } } }
同样要指定编码为UTF-8。
(41)解析XML的的两种方式:DOM & SAX
DOM解析慢,SAX解析快。Apache Digester是一个实现了SAX解析的Java库。
(42)创建List的更方便的途径:Google Guava
有了Google Guava,可以很方便进对集合类对象进行操作,例如创建一个List:
List<String> myList = Lists.newArrayList();
而我们平常会这样做:
List<String> myList = new ArrayList<String>();
再举一例:
Map<String, String> myMap = Maps.newHashMap();
可见用Google Guava会简单得多。这只是用Google Guava简化工作的一个非常简单的例子,还有更多很实用的功能,请参考其官网。
文章来源:http://www.codelast.com/
(43)Spring配置文件中的 & 字符转义
如果你用Spring来解析XML配置文件,并且在配置文件里的双引号中用了 & 字符:
<bean id="urlProcessor" class="com.codelast.URLProcessor"> <property name="url" value="http://www.codelast.com/search.php?time=2012-08-02&id=36" /> </bean>
那么,你就不能像上面那样直接写 & 字符,否则Spring解析的时候会报错:
Exception in thread "main" org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 71 in XML document from class path resource [abc.xml] is invalid; nested exception is org.xml.sax.SAXParseException: The reference to entity "XXX" must end with the ';' delimiter.
你应该把配置文件中的 & 字符换成:
&
这样就解决了。
(44)Spring JDBC配置编码,使得中文可以正确写入MySQL数据库
如下:
my_db_name.datasource.driver:com.mysql.jdbc.Driver my_db_name.datasource.url:jdbc:mysql://192.168.1.100:3306/my_db_name?characterEncoding=UTF-8 my_db_name.datasource.username:root my_db_name.datasource.password:XXXXXX
如上,你应该用“?characterEncoding=UTF-8”来指定编码为UTF-8,这样写入的中文才能正确显示,否则写入的中文可能会乱码或者显示为一堆问号。
(45)一些时间常量
利用 org.apache.commons.lang.time 包里的 DateUtils 类,我们可以轻易获取很多有用的时间常量:
DateUtils.MILLIS_PER_DAY:一天的毫秒数
DateUtils.MILLIS_PER_HOUR:一小时的毫秒数
DateUtils.MILLIS_PER_MINUTE:一分钟的毫秒数
DateUtils.MILLIS_PER_SECOND:一秒的毫秒数
还有更多,请看源码或文档。
(46)HashMap是不保证顺序的
按一定顺序添加到HashMap中的元素,遍历读出的顺序不一定是添加进去的顺序,如果要保持这种顺序不变,可以用LinkedHashMap.
(47)将一个Iterable<Element>集合中的所有元素添加到一个ArrayList中
利用Google Guava库,可以轻松做到这一点:
其中,values是一个 Iterable<String> 对象。
(48)如何配置log4j,使得可以将 INFO、ERROR 的日志输出到一个文件,其中 ERROR 的日志还同时会输出到另一个文件
要实现这种效果,你需要的是两个appender,其中一个appender是输出 INFO、ERROR 等日志的appender,另一个appender是只输出 ERROR(和以上级别)的appender:
log4j.rootLogger=INFO, A1, A2 log4j.logger.com.codelast=INFO log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender log4j.appender.A1.File=/example/code/all.log log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p %t (%F:%L) %c - %m%n log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender log4j.appender.A2.Threshold=ERROR log4j.appender.A2.File=/example/code/err.log log4j.appender.A2.layout=org.apache.log4j.PatternLayout log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p %t (%F:%L) %c - %m%n
文章来源:http://www.codelast.com/
其中,第二句代码指定了所有 com.codelast 域下的 INFO 级别以上的日志都会被记录下来,appender A1没有特别地指定 Threshold,所以它就使用了这个Threshold定义;而appender A2指定了 log4j.appender.A2.Threshold=ERROR,因此,它只会记录ERROR以上级别的日志。
这样,all.log文件中就会记录所有INFO、ERROR、FATAL的日志,而err.log只会记录ERROR、FATAL的日志。
(49)Thrift service中的“oneway”定义
如果Thrift service的一个方法被定义成“oneway”的,那么表示:客户端只会向server提交一个resquest,而不会监听server的任何response。oneway的方法必须是void的方法。
(50)IntelliJ部分快捷键
首先说一下修改IntelliJ快捷键的方法:在菜单 File→Settings→Keymap 中可以修改(至少对12.0.2版是这样的),在右上方的搜索框里输入快捷键的名称(快捷键是干什么用的)就可以定位到该快捷键的设定处。然后右键点击它,选择“Remove XXX”,先把原来的快捷键删除,然后还是在右键菜单中用“Add Keyboard Shortcut”来添加一个新的快捷键,就相当于修改了快捷键的设置了。
Alt+F1:假设你正在编辑一个代码文件,想要快速跳转到Project视图中,该代码文件所在的树形结点上,用这个快捷键就可以做到。该快捷键会弹出一个菜单,选择“Project View”即可跳转过去。
注意:Ubuntu中Alt+F1被系统占用了,你可以按照上面的方法来修改成Alt+F5(当然也可以修改成其他的,要找一个还没被占用的)。
Ctrl+Alt+O:优化import的package。例如,在Java文件中你定义了:import org.apache.log4j.Logger; 而你实际上并没有使用到log4j,那么这就是一个多余的import项,可以把它去掉。可以用这个快捷键让IntelliJ帮你完成优化工作。
(51)运行Java项目中的test时提示一大堆定义找不到的问题
如果你在IntelliJ中运行Java项目里的test,提示一大堆定义找不到,而实际上这些文件都是存在的,那么有可能通过重新编译整个项目来解决:
点击菜单的“Build”→“Rebuild Project”即可。
(52)生成随机数
可以使用Apache的 org.apache.commons.lang.RandomStringUtils 类来生成随机数,里面有N个方法,可以生成各种各样的随机数,基本上能满足各种要求了,详细请看这里。
举个例子,要生成5位数字的随机数,这样就可以:
RandomStringUtils.randomNumeric(5);
方便吧?
(53)Java读文件、写文件的最简单的方式
使用Apache的org.apache.commons.io.FileUtils的readFileToString()和writeStringToFile()方法,可以用一句代码将String写入文件,或者将文件中的内容读入String,详情请看这里。
文章来源:http://www.codelast.com/
(54)BufferedWriter写文件时,write方法不会立即写入
调用BufferedWriter的write方法写文件时,它不会立即写入,而是写到了缓冲区里,除非你调用flush方法刷新缓冲区。或者在写结束的时候调用close方法也可以达到同样的效果。
(55)Zookeeper自带的客户端zkCli.sh创建Zookeeper节点的方法
首先执行该脚本,进入交互模式:
./zkCli.sh
如果你要连接另一台服务器的Zookeeper,使用下面的命令即可:
./zkCli.sh -server host:port
其中,host是你要连接的Zookeeper服务器的地址,port是Zookeeper的端口。
“help”命令可以查看帮助:
[zk: localhost:2181(CONNECTED) 0] help ZooKeeper -server host:port cmd args connect host:port get path [watch] ls path [watch] set path data [version] delquota [-n|-b] path quit printwatches on|off create [-s] [-e] path data acl stat path [watch] close ls2 path [watch] history listquota path setAcl path acl getAcl path sync path redo cmdno addauth scheme auth delete path [version] setquota -n|-b val path
可猜出“create”命令可用于创建节点。该命令可带 -e 或 -s 参数执行,分别表示创建Ephemeral Node(临时的)和Sequence Node(顺序的且永久的),这两个参数可以同时使用。
如果不加参数,那么就表示创建一个永久节点,例如:
[zk: localhost:2181(CONNECTED) 2] create /codelast "node_info" Created /codelast
其中,第二个参数填的是节点的内容(注意:在这里,引号也会被当作是你填写的内容),必须要填写,不提供该参数则会创建失败。
如果我们创建一个Ephemeral Node:
[zk: localhost:2181(CONNECTED) 8] create -e /codelast "node_info" Created /codelast
那么退出该session(在此处即退出zkCli.sh工具)后,创建的临时节点就会消失。
如果创建一个Sequence Node,就会发现Zookeeper在你指定的节点名后添加了一串数字:
[zk: localhost:2181(CONNECTED) 2] create -s /codelast "node_info" Created /codelast0000000011
再执行一遍同样的命令,会发现那串数字在递增:
[zk: localhost:2181(CONNECTED) 3] create -s /codelast "node_info" Created /codelast0000000012
这说明,我们可以用一模一样的命令创建N个不同的结点,在某些情况下这是很有用的。
在创建了Sequence Node之后,退出zkCli.sh,再重新连接,会发现前面创建的Sequence Node还存在,这说明Sequence Node也是永久的。
文章来源:http://www.codelast.com/
我们也可以同时使用 -e -s 参数来创建一个临时的顺序节点:
[zk: localhost:2181(CONNECTED) 0] create -e -s /codelast "node_info" Created /codelast0000000015
在session断开之后,我们会发现该节点已不复存在。
(56)Java方法中的参数类型后跟三个点的作用
例如:
public void test(String... a) { for (String s : a) { System.out.println(s); } }
如上所示,当参数类型后面跟三个点的时候,a就被当作一个数组来用了。
(57)如何添加一个文件/目录到IntelliJ项目的classpath中
请看这里。
(58)thrift --gen java:private-members的作用
当你使用如下方法来生成一个thrift文件对应的源代码文件时:
thrift --gen java:private-members xxx.thrift
那么,生成的源码中,类的成员变量都是private的,而不是public的(public的是很不好的设计,但由于历史遗留原因,它们还是被保留了)。
(59)很简单的以追加内容的方式写文件的代码
FileWriter writer = new FileWriter("output.txt", true); writer.write(message.message); writer.close();
其中,FileWriter的构造函数的第二个参数为true决定了是以追加的方式写文件。
(60)Thrift在Java中为什么没有BufferedTransport
请看这里。
文章来源:https://www.codelast.com/
➤➤ 版权声明 ➤➤
转载需注明出处:codelast.com
感谢关注我的微信公众号(微信扫一扫):