编程技巧:使用整数同时进行多个true|false判断(修改版)
2015-11-06 00:00
525 查看
摘要: 使用整数int同时进行多个条件的判断,避免大量if...else语句,易于维护。
假设需要判断某银行用户的其中一个账号(profileA),币种(Currency)为人民币(CNY),余额是否大于1,0000,然后进行某业务逻辑处理。
情景二:验证文件的扩展名是否合格。
定义每个二进制位数上的含义(即标准),并在代码中以十六进制的形式表示;(其实十进制也可以,只是在十六进制下其实就是1/2/4/8这几个数字在不同的位上循环,比十进制数要直观,可以在下图感受一下)
将多个待验证的条件通过逻辑与(OR, "|")组合起来(token);
根据第一点的标准,计算出当前值(code);
若要判断满足token的所有条件,将当前值和token进行逻辑与(AND, "&")运算,所得结果再与token比较;
若要判断满足token的至少一个条件,将当前值和token进行逻辑与(AND, "&")运算,所得结果再与0比较;
在Modifier类中并没有进行多条件的组合,但我们可以在自定义的类中进行组合;
将要验证的编码(整数)传入,与modifier进行逻辑与(AND, "&")运算,再根据具体情况判断;
代码中:
转换成表格:
验证:主要看System.out.println();打印输出的几行即可,其他都是辅助理解。
在ToolBox类中定义各种标识的含义;
在main()中对profile进行验证并执行相应业务逻辑;
如需扩展,在ToolBox定义新的内容即可添加新的业务即可。
p.s:数字下划线是JDK 1.7的语法糖,仅有方便(人类)阅读的作用,编译时会自动去掉。如1_0000_0000、100_000_000、100000000这几个数字在编译后都一样,但极大地方便了阅读。
避免大量的if...else判断;
易于扩展维护代码;
二进制的计算,高效;
缺点
需要先定义作比较的条件和计算出具体值,占了一定的代码量;
初次接触的话可能不易理解;
与switch的比较
轻松进行多个条件的判断,且可以进行子集条件的判断,即对于满足A|B|C|D的条件,也会同时满足A|B、B|D或B|C|D等等。switch并不具备这样的能力。
Scene 情景假设
情景一:银行账户的快速判断;假设需要判断某银行用户的其中一个账号(profileA),币种(Currency)为人民币(CNY),余额是否大于1,0000,然后进行某业务逻辑处理。
情景二:验证文件的扩展名是否合格。
Abstract 概述
为了进行场景1的判断,需要判断/验证该账号是否为profileA、币种是否为CNY,余额是否大于1,0000这3种情况,在代码中可能会写出一大堆if...else语句,不仅不雅观,还不便于理解。如果使用一个整数int来同时标识多个判断的结果,就可以避免一大堆if...else的情况。当然这个例子只是作为demo说明情况,具体怎么处理还得根据实际出发,而且要是需要作更多判断,这个方法就会更实用。Description 详细说明
原理分析
对于计算机来说,所有数据都是由二进制数来表示,对于每一位(bit)来说,有0或1这2种情况,分别对应的boolean值为false和true。在Java中,每个int的大小为4 byte(注意是基本类型的int,而不是引用类型的Integer),一共有4*8=32位(bit),每一个位可对应一个boolean值的话,那么1个int最多可以同时对应32个boolean值。具体步骤
大概可分为3步:定义每个二进制位数上的含义(即标准),并在代码中以十六进制的形式表示;(其实十进制也可以,只是在十六进制下其实就是1/2/4/8这几个数字在不同的位上循环,比十进制数要直观,可以在下图感受一下)
将多个待验证的条件通过逻辑与(OR, "|")组合起来(token);
根据第一点的标准,计算出当前值(code);
若要判断满足token的所有条件,将当前值和token进行逻辑与(AND, "&")运算,所得结果再与token比较;
return (mod & modifier) == modifier;
若要判断满足token的至少一个条件,将当前值和token进行逻辑与(AND, "&")运算,所得结果再与0比较;
return (mod & modifier) != 0;
JDK中的实现:java.lang.reflect.Modifier
在java.lang.reflect.Modifier中定义了变量的修饰符(modifier,即staic/final/public/private等);在Modifier类中并没有进行多条件的组合,但我们可以在自定义的类中进行组合;
public static final int PUBLIC_STATIC_FINAL = PUBLIC | STATIC | FINAL;
将要验证的编码(整数)传入,与modifier进行逻辑与(AND, "&")运算,再根据具体情况判断;
return (mod & PUBLIC) != 0;
return (mod & PUBLIC_STATIC_FINAL) == PUBLIC_STATIC_FINAL;
代码中:
public class Modifier { public static final int PUBLIC = 0x00000001; public static final int PRIVATE = 0x00000002; public static final int PROTECTED = 0x00000004; public static final int STATIC = 0x00000008; public static final int FINAL = 0x00000010; public static final int SYNCHRONIZED = 0x00000020; public static final int VOLATILE = 0x00000040; public static final int TRANSIENT = 0x00000080; }
转换成表格:
java.lang.reflect.Modifier | 二进制 | 十进制 | 十六进制 |
---|---|---|---|
public | 0000,0001 | 2^0= 1 | 0x00000001 |
private | 0000,0010 | 2^1=2 | 0x00000002 |
protected | 0000,0100 | 2^2=4 | 0x00000004 |
static | 0000,1000 | 2^3=8 | 0x00000008 |
final | 0001,0000 | 2^4=16 | 0x00000010 |
synchronized | 0010,0000 | 2^5=32 | 0x00000020 |
volatile | 0100,0000 | 2^6=64 | 0x00000040 |
transient | 1000,0000 | 2^7=128 | 0x00000080 |
package com.scv.lawrence.multicompare; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import static com.scv.lawrence.multicompare.DemoTools.STATIC_FINAL; import static com.scv.lawrence.multicompare.DemoTools.compare; //为了减少篇幅,实际开发中个人不推荐使用静态导入 public class FirstStep { /* 定义了3个不同修饰符组合的变量(static、final),并在代码中验证 */ private static int age = 999; //age → static private static final String name = "Lawrence"; // name → static + final public final String gender = "Male"; //gender → final public static void main(String[] args) throws Exception { Field myAge = FirstStep.class.getDeclaredField("age"); int ageMod = myAge.getModifiers(); System.out.println("age的modifier(十进制): " + ageMod); System.out.println("\t" + "是否包含static和final:" + compare(ageMod, STATIC_FINAL)); System.out.println("\t" + "是否包含static:" + compare(ageMod, Modifier.STATIC)); Field myName = FirstStep.class.getDeclaredField("name"); int nameMod = myName.getModifiers(); System.out.println("************"); System.out.println("name的modifier(十进制): " + nameMod); System.out.println("\t" + "是否包含static和final:" + compare(nameMod, STATIC_FINAL)); System.out.println("\t" + "是否包含static:" + compare(nameMod, Modifier.STATIC)); Field myGender = FirstStep.class.getDeclaredField("gender"); int genderMod = myGender.getModifiers(); System.out.println("************"); System.out.println("gender的modifier(十进制): " + genderMod); System.out.println("\t" + "是否包含static和final:" + compare(genderMod, STATIC_FINAL)); System.out.println("\t" + "是否包含static:" + compare(genderMod, Modifier.STATIC)); } } /* output: * * age的modifier(十进制): 10 * 是否包含static和final:false * 是否包含static:true * ************ * name的modifier(十进制): 26 * 是否包含static和final:true * 是否包含static:true * ************ * gender的modifier(十进制): 17 * 是否包含static和final:false * 是否包含static:false */
Example 场景应用
场景一 银行账户
自定义Profile类,在实例化的时候就计算并保存其类型;在ToolBox类中定义各种标识的含义;
在main()中对profile进行验证并执行相应业务逻辑;
package com.scv.lawrence.multicompare; public class ThirdStep { public static void main(String[] args) { Profile[] profiles = {new Profile("ABC0001", "CNY", 12_0000), new Profile("SRC0001", "CNY", 21_0000), //target profile new Profile("ZZZ666GRE", "USD", 9000)}; for(Profile p: profiles){ if(ToolBox.isTargetProfile(p, ToolBox.PRO_A_CNY_GT)){ //Do something. System.out.println("Got target profile."); }; } } } class ToolBox{ public static final int PROFILE_A = 0x0000_0001; //0001 public static final int CNY = 0x0000_0002; //0010 public static final int GT_10K = 0x0000_0004; //0100 public static final int LT_10K = 0x0000_0008; //1000 public static final int PRO_A_CNY_GT = PROFILE_A | CNY | GT_10K; //0111,profileA、币种为人民币、余额大于1,0000 public static final int PRO_A_CNY_LT = PROFILE_A | CNY | LT_10K; //1111,profileA、币种为人民币、余额不足1,0000 protected static void setToken(Profile p){ if("SRC0001".equals(p.getName())) p.token += 0x0000_0001; if("CNY".equals(p.getCurrency())) p.token += 0x0000_0002; if(p.getBalance() > 1_0000) p.token += 0x0000_0004; } public static boolean isTargetProfile(Profile p, int mod){ return (p.getToken() & mod) == mod; } } class Profile{ private String name; private String currency; private double balance; protected int token; public int getToken(){ return this.token; } public Profile() {} public Profile(String name, String currency, double balance){ this.name = name; this.currency = currency; this.balance = balance; ToolBox.setToken(this); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCurrency() { return currency; } public void setCurrency(String currency) { this.currency = currency; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; }; }
如需扩展,在ToolBox定义新的内容即可添加新的业务即可。
p.s:数字下划线是JDK 1.7的语法糖,仅有方便(人类)阅读的作用,编译时会自动去掉。如1_0000_0000、100_000_000、100000000这几个数字在编译后都一样,但极大地方便了阅读。
场景二 验证多个文件扩展名
值得注意的是,由于是判断是否满足一个或多个条件,因此将判断表达式改为return (code & RULER) != 0;
package com.scv.lawrence.multicompare; public class SecondStep { private static String[] fileNames = {"picA.jpg", "picB.jpg", "picC.png", "picD.gif", "picE.jpeg", "picF.abc"}; public static void main(String[] args) { checkSuffix(fileNames); } public static boolean checkSuffix(String[] fileNames){ boolean flag = true; for(String s : fileNames){ int c = s.lastIndexOf("."); if(c != -1){ String suffix = s.substring(c + 1).toLowerCase(); int code = getCode(suffix); //获取文件扩展名并判断 flag = Ruler.isAllow(code); System.out.println(s + ": " + (flag ? "pass" : "not pass")); if(!flag) return false; //只要有一个不合格的格式就直接返回false }else{ return false; //没有扩展名,直接返回false } } return flag; } public static int getCode(String suf){ int code = 0; switch(suf){ case "jpg": //switch语句使用字符串作判断条件也是jdk1.7的特性,其实质仍然是int(编译后计算hashCode) code = Ruler.JPG; break; case "jpeg": code = Ruler.JPEG; break; case "png": code = Ruler.PNG; break; case "gif": code = Ruler.GIF; break; default: code = Ruler.DEFAULT; break; } return code; } } class Ruler{ public static final int DEFAULT = 0x0; public static final int JPG = 0x1; public static final int JPEG = 0x2; public static final int PNG = 0x4; public static final int GIF = 0x8; public static final int RULER = JPG | JPEG | PNG | GIF; //只允许jpg、jpeg、png、gif格式的文件 public static boolean isAllow(int code){ return (code & RULER) != 0; } }
Summary 总结
优点避免大量的if...else判断;
易于扩展维护代码;
二进制的计算,高效;
缺点
需要先定义作比较的条件和计算出具体值,占了一定的代码量;
初次接触的话可能不易理解;
与switch的比较
轻松进行多个条件的判断,且可以进行子集条件的判断,即对于满足A|B|C|D的条件,也会同时满足A|B、B|D或B|C|D等等。switch并不具备这样的能力。
Reference 参考
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统