【问题标题】:Can I use a 'byte' for boolean array?我可以为布尔数组使用“字节”吗?
【发布时间】:2016-03-21 13:04:48
【问题描述】:

在我们正在制作的应用程序(iOS/Swift、Android)中,我们有一个设置页面,用于当用户想要接收推送通知时。其中一项设置是供用户选择一周中的哪几天。

我的问题是关于如何将此选项存储为一个变量,而不是七个布尔值。该设置将被发送到服务器/数据库进行存储,我想我们可以简单地在数据库中使用单个字节字段。 而不是monday=true, tuesday=false, ...,我想使用例如'10001010',其中1为真,0为假,这将转换为monday=true(1), tuesday=false(0), etc(假设星期一是一周的第一天,它是..)。

这是存储此类数据的有效方式吗?我可以创建一个这样的字节吗?还是使用 string/char[] "10001010" 是一种更常用的做法?或者数据库(例如 MySQL)可以将 bool[] (10001010) 存储为一个字段吗?或者还有其他更好的做法吗? 用于权限的方法也想到了(你知道,777,只是简化了)

当然,有些变体需要服务器对变量使用相同的逻辑,但在这种情况下没问题。

简短的解释,我需要七个布尔值,一个用于一周中的每一天,我想比每天一个变量更有效地存储它。是否有“最佳实践”?

【问题讨论】:

  • 考虑BitSet
  • 从内存的角度来看,使用 7 个布尔值的字节或位集可能是可行的方法,从维护的角度来看,我可能会使用更容易阅读的东西,例如像1010000x-x---- 这样的字符串。如果数据库列不需要支持的只是基本的 crud 功能(例如,没有排序,这些列上没有连接等),您还可以将设置保存为 JSON 字符串等。
  • “有‘最佳实践’吗?” - 是的。最佳实践是自己了解利弊,并将这些知识应用于问题。最佳做法是不要问是否有“最佳做法”!

标签: java mysql swift


【解决方案1】:

这个问题“暴露”了过早的优化:

  • 7 个布尔变量占用的空间可以忽略不计(可能是 7 x 4 字节)...除非您需要同时在内存中保存数十万个用户设置对象。

    李>
  • 网络带宽的差异可以忽略不计......除非您发送数百万条消息。

  • 数据库表空间的差异可以忽略不计...除非您在数据库中存储数百万条用户记录。


这是存储此类数据的有效方式吗?

定义“有效”。但是是的,它(大部分)有效。

我想比每天一个变量更有效地存储它

是的……但有必要这样做吗?您是否量化了通过这种(假定的)效率可以获得多少收益。


对于它的价值,将多个布尔值打包成一个字节/字/任何东西都会受到许多惩罚。其中包括:

【讨论】:

  • 这里的其他答案给了我我所要求的,但你给了我更多!您关于 SQL 查询惩罚的注释是我没有想到的,听起来很正确。将查询选择字段,例如where monday=true,我同意仅在该查询上处理数十万行时,这可能是一个严重的惩罚。这对我来说是正确的答案。但是,对于问题仍然有效的其他用户,我建议查看其他答案。
【解决方案2】:

你可以这样存储它。

class A {
    public static final int MONDAY = 0;
    ...
    public static final int SUNDAY = 6;

    // call with the above defined constants for day
    public byte addDay(byte b, int day) {
        return (byte) (b | (1 << day));
    }

    public boolean isDaySet(byte b, int day) {
        return ((b >> day) & 1) == 1 ;
    }
}

这当然只是一些快速而肮脏的示例代码,但我希望它能让概念清晰。

【讨论】:

  • 感谢您的编辑。忘了从我的 IDE 中接管它;)。
【解决方案3】:

只需对字节进行一些按位运算。示例代码

enum Days {
    MON,
    TUE,
    WED,
    THU,
    FRI,
    SAT,
    SUN
}

public static void main(String[] args) {

    byte encode = (byte)0b1010000;

    for ( Days d : Days.values() ) {
        boolean present = (encode & 1<<d.ordinal()) != 0;
        System.out.println(d + " " + present);
    }

    System.out.println("Adding MON, removing SUN");

    encode |= (1<<Days.MON.ordinal());
    encode &= ~(1<<Days.SUN.ordinal());

    for ( Days d : Days.values() ) {
        boolean present = (encode & 1<<d.ordinal()) != 0;
        System.out.println(d + " " + present);
    }

}

当然,你应该把它包装成一些更好的类/访问器方法,也许直接在 Days 枚举中添加一个准备使用的值作为字段而不是使用 1

【讨论】:

    【解决方案4】:

    考虑使用 EnumSet,就像 Joshua Bloch 的“Effective Java”中的第 32 条所建议的那样。 (EnumSet 内部是 BitVectors)

    使用java.time.DayOfWeek 作为枚举类型。

    Set 中包含的星期几是您的用户选择的。其他没有被选中。

    EnumSet<DayOfWeek> selectedDays = EnumSet.of(DayOfWeek.MONDAY, DayOfWeek.FRIDAY);
    
    selectedDays.contains(DayOfWeek.MONDAY); // true
    selectedDays.contains(DayOfWeek.TUESDAY); // false
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多