建议25: 不要让四舍五入亏了一方 本建议还是来重温一个小学数学问题:四舍五入.四舍五入是一种近似精确的计算方法,在Java 5之前,我们一般是通过使用Math.round来获得指定精度的整数或小数的,这种方法使用非常广泛,代码如下: public class Client { public static void main(String[] args) { System.out.println("10.5近似值:" + Math.round(10.5)); System.out.pr…
建议16: 易变业务使用脚本语言编写 Java世界一直在遭受着异种语言的入侵,比如PHP.Ruby.Groovy.JavaScript等,这些“入侵者”都有一个共同特征:全是同一类语言—脚本语言,它们都是在运行期解释执行的.为什么Java这种强编译型语言会需要这些脚本语言呢?那是因为脚本语言的三大特征,如下所示: 1.灵活.脚本语言一般都是动态类型,可以不用声明变量类型而直接使用,也可以在运行期改变类型. 2.便捷.脚本语言是一种解释型语言,不需要编译成二进制代码,也不需要像Java一样生成字节…
在Java中一涉及到中文处理就会冒出很多的问题来,其中的排序也是一个让人头疼的问题,看代码: import java.util.Arrays; public class Client { public static void main(String[] args){ String[] strs = {"张三(Z)","李四(L)","王五(W)"}; //排序,默认是升序 Arrays.sort(strs); int i=0; for(Strin…
一.分析  字符串的操作,诸如追加.合并.替换.倒序.分隔等,都是在编码过程中经常用到的,而且Java也提供了append.replace.reverse.split等方法来完成这些操作,它们使用起来确实方便,但是更多的时候,需要使用正则表达式来完成复杂的处理. 二.场景  统计一篇文章中的单词的数量,代码如下: import java.util.Scanner; public class Client { public static void main(String[] args) { //接…
我们知道Set与List的最大区别就是Set中的元素不可以重复(这个重复指的equals方法的返回值相等),其他方面则没有太大的区别了,在Set的实现类中有一个比较常用的类需要了解一下:TreeSet,该类实现了类默认排序为升序的Set集合,如果插入一个元素,默认会按照升序排列(当然是根据Comparable接口的compareTo的返回值确定排序位置了),不过,这样的排序是不是在元素经常变化的场景中也适用呢?我们来看例子: import java.util.SortedSet; import…
Vector是ArrayList的多线程版本,HashTable是HashMap的多线程版本,这些概念我 们都很清楚,也被前辈嘱咐过很多次,但我们经常会逃避使用Vector和HashTable,因为用 得少,不熟嘛!只有在真正需要的时候才会想要使用它们,但问题是什么时候算真正需要呢?我们来看一个例子,看看使用线程安全的Vector是否可以解决问题,代码如下: import java.util.ArrayList; import java.util.List; import java.util.R…
在系统开发中我们经常会使用HashMap作为数据集容器,或者是用缓冲池来处理,一般很稳定,但偶尔也会出现内存溢出的问题(OutOfMemory错误),而且这经常是与HashMap有关的.而且这经常是与HashMap有关的.比如我们使用缓冲池操作数据时,大批量的增删改产操作就可能会让内存溢出,下面建立一段模拟程序,重现该问题,看代码: import java.util.HashMap; import java.util.Map; public class Client { public stati…
在初中代数中,我们经常会求两个集合的并集.交集.差集等,在Java中也存在着此 类运算,那如何实现呢? 一提到此类集合操作,大部分的实现者都会说:对两个集合进行遍历,即可求出结果.是的,遍历可以实现并集.交集.差集等运算,但这不是最优雅的处理方式.下面来看看如何进行更优雅.快速.方便的集合操作. (1) 并集,(2)交集,(3)差集(补集),(4)无重复并集. 也叫做合集,把两个集合加起来即可,这非常简单,代码如下: import java.util.ArrayList; import java…
对一个列表进行检索时,我们使用的最多的是indexOf方法,它简单好用,而且也不会出错,虽然它只能检索到第一个符合条件的值,但是我们可以生成子列表后再检索.这样也就可以查找到所有符合条件的值了. Collections工具类也提供了一个检索的方法:binarySearch,这个是干什么的?该方法也是对一个列表进行检索的,可以查找出指定的索引值,但是在使用这个方法时就有一些注意事项,看代码: import java.util.ArrayList; import java.util.Collecti…
List接口提供了subList方法,其作用是返回一个列表的子列表.这与String类的subString有点类似.但是他们的功能是否相同?看代码: import java.util.ArrayList; import java.util.List; public class Client { public static void main(String[] args) { //定义一个包含两个字符串的列表 List<String> c = new ArrayList<String>…
来看一个判断列表相等的例子,看代码: import java.util.ArrayList; import java.util.Vector; public class Client { public static void main(String[] args) { ArrayList<String> strs = new ArrayList<String>(); strs.add("A"); Vector<String> strs2 = new…
一.场景: 我们来看一个场景,统计一个省的各科高考科目考试的平均分. 当然使用数据库中的一个SQL语句就能求出平均值,不过这个不再我们的考虑之列,这里只考虑使用纯Java的方式来解决.(由于我的机器配置比较好,用80万的数据量有点小,各个统计结果不明显,不能更加显著的说明明问题...这里改为800万) 看代码: import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.uti…
上一个建议之处了asList方法在转换基本类型数组时候存在的问题,在看下asList方法返回的列表有何特殊的地方.看代码: import java.util.Arrays; import java.util.List; public class Client { //枚举,声明一个星期 enum Week{Sun,Mon, Tue, Wed,Thu,Fri,Sat} public static void main(String[] args) { //工作日 Week[] workDays =…
开发中经常用到Arrays和Collections这两个工具类. 在数组和列表之间进行切换.非常方便.但是也会遇到一些问题. 看代码: import java.util.Arrays; import java.util.List; public class Client { public static void main(String[] args) { int[] data = {1,2,3,4,5}; List list = Arrays.asList(data); System.out.p…
注解的写法和接口很类似,都采用了关键字interface,而且都不能有实现代码,常量定义默认都是pulbic static final类型的. 他们的主要不同点是:注解在interface前加上@字符,而且不能继承,不能实现,这经常会给我们的开发带来一些障碍. 分析一个ACL(Access Contorl List ,访问控制列表)设计案例..看看如何避免这些障碍. ACL中有三个重要的元素: 1.资源,有哪些信息是要被控制起来的. 2.权限级别,不同的访问者在规划在不同的级别中. 3.控制器(…
为了更好的使用枚举,Java提供了两个枚举集合:EnumSet和EnumMap,这两个集合的使用方法都比较简单,EnumSet表示其元素必须是某一枚举的枚举项,EnumMap表示Key值必须是某一枚举的枚举项,由于枚举类型的实例数量固定并且有限,相对来说,EnumSet和EnumMap的效率会比其他Set和Map要高. 虽然EnumSret很好用,但是它有一个隐藏的特点.项目中可能定义非常多的枚举项,然后通过EnumSet访问,遍历,但它对不同的枚举数量有不同的处理方式.为了进行对比,我们定义两…
工厂方法模式(Factory Method Patter)是"创建对象的接口",让子类决定实例化哪一个类,并使一个类的实例化延迟到其子类.工厂方法模式在我们的开发工作中,经常会用到. 下面以汽车制造为例,看看一般的工厂方法模式是如何实现的,代码如下: public class Client { public static void main(String[] args) { //生产车辆 Car car = CarFactory.createCar(FordCar.class); }…
每个枚举都是java.lang.Enum的子类,都可以访问Enum类提供的方法,比如hashCode(),name(),valueOf()等..... 其中valueOf()方法会把一个String类型的名称转变为枚举项,也就是枚举项中查找出字面值与该参数相等的枚举项,虽然这个方法很简单,但是JDK却做了一个对于开发人员来说并不简单的处理: 看代码: import java.util.Arrays; import java.util.List; public class Client { pub…
使用枚举定义常量时,会伴有大量的switch语句判断,目的是伪类每个枚举项解释其行为,例如: public class Client { public static void main(String[] args) { doSports(null); } public static void doSports(Season season) { switch (season) { case Spring: System.out.println("春天放风筝"); break; case…
上一个建议解释了为什么要使用forName,本建议就说说哪些地方不适合使用动态加载. 如果forName要加载一个类,那它必须是一个类------8中基本类型就排除在外.它们不是一个具体的类. 其次它必须具有可追溯的类路径...否则就会报ClassNotFoundException. 在Java中,数组是一个非常特殊的类,虽然它是一个类,单没有定义类路径. public class Client { public static void main(String[] args) throws Ex…
动态加载(Dynamic Loading)是指在程序运行时加载需要的类库文件,对Java程序来说,一般情况下,一个类文件在启动时或首次初始化时会被加载到内存中,而反射则可以在运行时再决定是否需要加载一个类,比如从Web上接受一个String参数作为类名,然后在JVM中加载并初始化,这就是动态加载,此动态加载通常是通过Class.forName(String)实现的,只是这个forName()方法到底是什么意思? 我们知道一个类文件只有在被加载到内存中后才可能生成实例对象,也就是说一个对象的生成必…
Java的Class类提供了很多的getDeclaredxxx方法和getxxx方法,例如getDeclaredmethod和getMethod成对出现,getDeclaredConstructors和getConstructors也是成对出现. 那这两者有什么区别呢? import java.lang.reflect.Method; public class Client { public static void main(String[] args) throws Exception { /…
Java语言是先把Java源文件编译成后缀为class的字节码文件,然后再通过ClassLoader机制把这些类文件加载到内存中,最后生成实例执行的,这是Java处理的基本机制,但加载到内存中的数据是如何描述一个类的呢? 比如在Dog.class文件中定义了的是一个Dog类,那它在内存中是如何展现的呢? Java使用一个元类(MetaClass)来描述加载到内存中的类数据,这就是Class类,它是一个描述类的类对象,比如Dog.class文件加载到内存中后就是一个Class实例对象描述. 因为C…
从哲学上来说,很难描述一个具体的人,你可以描述它的长相,性格,工作等,但是人都是有多重身份的,估计只有使用多个And(与操作)将所有的描述串联起来才能描述一个完整的人,人在不同的环境中角色也在不断的更换. 用Java程序来对一类人进行管理,比如在公交车费优惠系统中,对部分人员,工资低于2500元的上班族而且是站立着的乘客 车费打8折. 这里的类型参数有两个限制条件,一为上班族,二为乘客,具体到程序中就是一个泛型参数有两个上界Upper Bound,首先定义两个接口以及实现类: //职员 inte…
List接口的toArray方法可以把一个结合转化为数组,但是使用不方便,toArray()方法返回的是一个Object数组,所以需要自行转变. toArray(T[] a)虽然返回的是T类型的数组,但是还是需要传入一个T类型的数组,这也挺麻烦的.我们期望输入的是一个泛型化的list,这样就能转化为泛型数组了. 看代码: import java.util.Arrays; import java.util.List; public class Client<T> { public static…
什么叫做协变(covariance)和逆变(contravariance)? 在变成语言的类型框架中,协变和逆变是指宽类型和窄类型在某种情况下(如参数,泛型,返回值)替换或交换的特性,简单的说,协变是用一个窄类型替换宽类型,而逆变则是用宽类型覆盖窄类型. 协变:宽类型------>窄类型 逆变:窄类型------>宽类型 class Base{ public Number doStuff(){ return 0; } } class Sub extends Base{ @Override pu…
Java泛型支持通配符(Wildcard),可以单独使用一个"?"表示任意类,也可以使用extends关键字标识某一类(接口)的子类型,还可以使用super关键字标识某一类(接口)的父类型,但问题是什么时候该用extends,什么时候该用super? (1)泛型结构只参与"读"操作则限定上界(extends 关键字) 于都如下代码,看业务逻辑操作是否还能继续? import java.util.Arrays; import java.util.List; publi…
Arrays工具类有一个方法asList可以把一个变长参数或数组变成列表,但是它有一个缺点:它所生成的List长度是不可改变的,而这在我们的项目开发中很不方便. import java.util.Arrays; import java.util.List; public class Client { public static void main(String[] args) { String[] strArray = {"1","18","71"…
泛型类型在编译期被擦除,我们在类初始化时将无法获得泛型的具体参数,比如这样的代码: class Foo<T>{ //private T t =new T();//报错Cannot instantiate the type T //private T[] tArray= new T[5];//报错Cannot create a generic array of T private List<T> list= new ArrayList<T>(); } 这段代码有什么问题?…
泛型可以减少强制类型的转换,可规范集合的元素类型,还可以提高代码的安全性和可读性,正是因为有了这些优点,自从Java引入泛型之后,项目的编码规则上便多了一条,优先使用泛型. Java泛型(Generic)的引入加强了参数类型的安全性,减少了类型的转换,它与C++中的模板templates比较类似.但是有一点,Java的反省在编译期有效,在运行期被删除,也就是说所有的泛型参数类型在编译后都会被清除掉. 看如下代码: import java.util.List; public class Foo {…