编程技巧:使用整数同时进行多个true|false判断

情景 :

假设需要判断某银行用户的其中一个账号(profileA),币种(Currency)为人民币(CNY),余额是否大于1,0000,然后进行某业务逻辑处理。

概述:

为了进行这种判断,需要判断/验证该账号是否为profileA、币种是否为CNY,余额是否大于1,0000这3种情况,在代码中可能会写出一大堆if...else语句,不仅不雅观,还不便于理解。如果使用一个整数int来同时标识多个判断的结果,就可以避免一大堆if...else的情况。当然这个例子只是作为demo说明情况,具体怎么处理还得根据实际出发,而且要是需要作更多判断,这个方法就会更实用。



分析说明:

对于计算机来说,所有数据都是由二进制数来表示,对于每一位(bit)来说,有0或1这2种情况,分别对应的boolean值为false和true。在Java中,每个int的大小为4 byte(注意是基本类型的int,而不是引用类型的Integer),一共有4*8=32位(bit),每一个位可对应一个boolean值的话,那么1个int最多可以同时对应32个boolean值。

以JDK中的实现,java.lang.reflect.Modifier为例:

  1. 定义每个二进制位数上的含义(modifier),并得到相应十六进制数;(其实十进制也可以,只是在十六进制下其实就是1/2/4/8这几个数字在不同的位上循环,比十进制数要直观,可以在下图感受一下)
  2. 如果同时验证多个条件,可以通过逻辑与(OR, "|")将多个条件组合起来。例如可以自定义“同时满足public、static、final这3个修饰词”这个条件:
    • public static final int PUBLIC_STATIC_FINAL = PUBLIC | STATIC | FINAL;
  3. 将要验证的编码(整数)传入,与modifier进行逻辑与(AND, "&")运算,所得结果再与modifier比较即可;
    • return (mod & modifier) == modifier;

 1 public class Modifier{
 2     public static final int PUBLIC = 0x00000001;    //0001
 3     public static final int PRIVATE = 0x00000002;    //0010
 4     public static final int PROTECTED = 0x00000004;    //0100
 5     public static final int STATIC = 0x00000008;    //1000
 6     ......
 7     public static boolean isPublic(int mod) {
 8         return (mod & PUBLIC) != 0;
 9     }
10     ......
11 }

展开/收起

验证:主要看System.out.println();打印输出的几行即可,其他都是辅助理解。

 1 package com.scv.lawrence;
 2 import java.lang.reflect.Field;
 3 import java.lang.reflect.Modifier;
 4
 5 public class Demo {
 6     public static final int STATIC_FINAL = Modifier.STATIC | Modifier.FINAL;
 7     public static final int PUBLIC_STATIC_FINAL = Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL;
 8
 9     public static boolean compare(int mod, int token){
10         return (mod & token) == token;
11     }
12
13     private static int age = 999;
14     private static final String name = "Lawrence";
15     public final String gender = "Male";
16
17     public static final int PUBLIC_STATIC = Modifier.PUBLIC | Modifier.STATIC;
18
19     public static void main(String[] args) throws Exception {
20         Field myAge = Demo.class.getDeclaredField("age");
21         Field myName = Demo.class.getDeclaredField("name");
22         Field myGender = Demo.class.getDeclaredField("gender");
23
24         int ageMod = myAge.getModifiers();
25         int nameMod = myName.getModifiers();
26         int genderMod = myGender.getModifiers();
27
28         System.out.println("age的modifier(十进制): " + ageMod);
29         System.out.println("\t" + "是否包含static和final:" + compare(ageMod, STATIC_FINAL));
30         System.out.println("\t" + "是否包含static:" + compare(ageMod, Modifier.STATIC));
31
32         System.out.println("************");
33         System.out.println("name的modifier(十进制): " + nameMod);
34         System.out.println("\t" + "是否包含static和final:" + compare(nameMod, STATIC_FINAL));
35         System.out.println("\t" + "是否包含static:" + compare(nameMod, Modifier.STATIC));
36
37         System.out.println("************");
38         System.out.println("gender的modifier(十进制): " + genderMod);
39         System.out.println("\t" + "是否包含static和final:" + compare(genderMod, STATIC_FINAL));
40         System.out.println("\t" + "是否包含static:" + compare(genderMod, Modifier.STATIC));
41     }
42
43 }
44
45 /* output:
46  *
47  * age的modifier(十进制): 10
48  * 是否包含static和final:false
49  * 是否包含static:true
50  * ************
51  * name的modifier(十进制): 26
52  * 是否包含static和final:true
53  * 是否包含static:true
54  * ************
55  * gender的modifier(十进制): 17
56  * 是否包含static和final:false
57  * 是否包含static:false
58  */

展开/收起



场景应用:

  1. 自定义Profile类,在实例化的时候就计算并保存其类型;
  2. 在ToolBox类中定义各种标识的含义;
  3. 在main()中对profile进行验证并执行相应业务逻辑;

 1 package com.scv.lawrence;
 2
 3 public class Fragment {
 4
 5     public static void main(String[] args) {
 6         Profile[] profiles = {new Profile("ABC0001", "CNY", 12_0000),
 7                         new Profile("SRC0001", "CNY", 21_0000),    //target profile
 8                         new Profile("ZZZ666GRE", "USD", 9000)};
 9
10         for(Profile p: profiles){
11             if(ToolBox.isTargetProfile(p, ToolBox.PRO_A_CNY_GT)){
12                 //Do something.
13                 System.out.println("Got target profile.");
14             };
15         }
16
17     }
18
19 }
20
21 class ToolBox{
22     public static final int PROFILE_A = 0x0000_0001;    //0001
23     public static final int CNY = 0x0000_0002;    //0010
24     public static final int GT_10K = 0x0000_0004;    //0100
25     public static final int LT_10K = 0x0000_0008;    //1000
26
27     public static final int PRO_A_CNY_GT = PROFILE_A | CNY | GT_10K;    //0111,profileA、币种为人民币、余额大于1,0000
28     public static final int PRO_A_CNY_LT = PROFILE_A | CNY | LT_10K;    //1111,profileA、币种为人民币、余额不足1,0000
29
30     protected static void setToken(Profile p){
31         if("SRC0001".equals(p.getName())) p.token += 0x00000001;
32         if("CNY".equals(p.getCurrency())) p.token += 0x00000002;
33         if(p.getBalance() > 1_0000) p.token += 0x00000004;
34     }
35
36     public static boolean isTargetProfile(Profile p, int mod){
37         return (p.getToken() & mod) == mod;
38     }
39 }
40
41 class Profile{
42     private String name;
43     private String currency;
44     private double balance;
45     protected int token;
46
47     public int getToken(){
48         return this.token;
49     }
50
51     public Profile() {}
52     public Profile(String name, String currency, double balance){
53         this.name = name;
54         this.currency = currency;
55         this.balance = balance;
56         ToolBox.setToken(this);
57     }
58     public String getName() {
59         return name;
60     }
61     public void setName(String name) {
62         this.name = name;
63     }
64     public String getCurrency() {
65         return currency;
66     }
67     public void setCurrency(String currency) {
68         this.currency = currency;
69     }
70     public double getBalance() {
71         return balance;
72     }
73     public void setBalance(double balance) {
74         this.balance = balance;
75     };
76
77
78 }

如要添加新的业务,只需要在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并不具备这样的能力。


如有纰漏,还望指正。

时间: 2024-10-05 10:37:27

编程技巧:使用整数同时进行多个true|false判断的相关文章

Python高效编程技巧

下面我挑选出的这几个技巧常常会被人们忽略,但它们在日常编程中能真正的给我们带来不少帮助. 1. 字典推导(Dictionary comprehensions)和集合推导(Set comprehensions) 大多数的Python程序员都知道且使用过列表推导(list comprehensions).如果你对list comprehensions概念不是很熟悉——一个list comprehension就是一个更简短.简洁的创建一个list的方法. >>> some_list = [1,

VC/MFC 编程技巧大总结

1 toolbar默认位图左上角那个点的颜色是透明色,不喜欢的话可以自己改. 2 VC++中 WM_QUERYENDSESSION WM_ENDSESSION 为系统关机消息. 3 Java学习书推荐:<java编程思想> 4 在VC下执行DOS命令 a. system("md c:\\12"); b. WinExec("Cmd.exe /C md c:\\12", SW_HIDE); c. ShellExecute ShellExecute(NULL,

ZStack中的编程技巧

1. 像函数一样使用的宏 //这个宏,用来被其他宏使用,构造一个正确有效的表达式.这个适合于一些离散语句的组合,不适合函数的重新命名 #define st(x)      do { x } while (__LINE__ == -1) 例如:#define aps_GroupsRemaingCapacity() ( APS_MAX_GROUPS - aps_CountAllGroups() ) 上述的这个宏,调用的其他函数来实现其功能,因此,不适合使用st()宏. 使用场景:  aps_Grou

【VC编程技巧】窗体?3.5对单文档或者多文档程序制作启动画面

(一)概要: 文章描述了怎样通过Visual C++ 2012或者Visual C++ .NET,为单文档或者多文档程序制作启动画面.在Microsoft Visual Studio 6.0中对于单文档程序(SDI)我们可以很方便利用微软提供的组件Visual C++ Component (Splash Screen).因为在Microsoft Visual Studio 6.0以后的版本或者Visual C++ .NET没有提供这个组件,我们可以通过自定义对话框来实现Splash Screen

单片机应用编程技巧问答

1. C语言和汇编语言在开发单片机时各有哪些优缺点? 答:汇编语言是一种用文字助记符来表示机器指令的符号语言,是最接近机器码的一种语言.其主要优点是占用资源少.程序执行效率高.但是不同的CPU,其汇编语言可能有所差异,所以不易移植. C语言是一种结构化的高级语言.其优点是可读性好,移植容易,是普遍使用的一种计算机语言.缺点是占用资源较多,执行效率没有汇编高. 对于目前普遍使用的RISC架构的8bit MCU来说,其内部ROM.RAM.STACK等资源都有限,如果使用C语言编写,一条C语言指令编译

编程技巧之表格驱动编程

/* Image format-dependent operations. */ typedef struct { jas_image_t *(*decode)(jas_stream_t *in, char *opts); /* Decode image data from a stream. */ int (*encode)(jas_image_t *image, jas_stream_t *out, char *opts); /* Encode image data to a stream.

Phaser 编程技巧

2015年2月6日 欢迎! 在连续几周讨论了平台跳跃游戏的机制之后,我们也应该休息一下了.因此,本周的教程将基于论坛上经常谈论的特性:网格运动,或者可以说得更加明确一点:如何像Pacman(译者注:在红白机上叫做吃豆子,或者小精灵)那样在网格中移动. 我们本周讨论的代码可以让玩家优雅地在瓦片地图中移动,在很小的空间中转弯.我们还将构建Pacman游戏的核心代码. 获取源代码 在这里我只会着重高亮最重要的部分代码.所以请先浏览一下代码.如果你对一些代码有疑问,你可以去论坛询问. 运行/编辑汽车游戏

java命名规范和编程技巧

一个好的java程序首先命名要规范. 命名规范 定义这个规范的目的是让项目中所有的文档都看起来像一个人写的,增加可读性,方便维护等作用 Package 的命名 Package 的名字应该都是由一个小写单词组成. Class 的命名 Class 的名字必须由大写字母开头而其他字母都小写的单词组成 Class 变量的命名 变量的名字必须用一个小写字母开头,后面的单词用大写字母开头. Static Final 变量的命名  Static Final 变量的名字应该都大写,并且指出完整含义. 参数的命名

分享25个实用的博客,有助你提高编程技巧

编程是一个不断变化的领域,一旦你选择了它作为你的职业,你就不可能停下学习的脚步了.因为科技的发展月新日异,要跟得上它发展的脚步,你必须不断地努力学习.在Forbes.com最近发表的一篇文章(25 Practical Blogs To Sharpen Your Coding Skills)中,作者Tomas Laurinavicius 推荐了25个他认为很适合程序员或学习编程的人在工作或学习中阅读的博客. 1. Scott Hanselman 在微软担任网络平台开发的Scott Hanselma