2

我需要创建一个用于改组的种子,种子应该基于一个 id(int)和当前日期(没有时间)。这是为了保留一天的 id 排序并在第二天更改它。我现在有以下方法:

private static long getSeedForShuffle(int id)
{
    Date date = new Date();
    Calendar cal = MyConstants.UTC_CALENDAR;
    cal.setTime(date);
    int year = cal.get(Calendar.YEAR);
    int month = cal.get(Calendar.MONTH);
    int day = cal.get(Calendar.DAY_OF_MONTH);
    double seed = id * 1e8 + year * 1e4 + month * 1e2 + day;
    return (long) seed;
}

这在 MyConstants 中:

public class MyConstants {
    public static final Calendar UTC_CALENDAR = Calendar.getInstance(TimeZone
                                                       .getTimeZone("UTC"));
}

有什么方法可以避免每次调用该方法时都创建新的日期对象?即有比做更好的事情吗

Date date = new Date();

在该getSeedForShuffle方法中,由于该方法只需要当前的日期、月份和年份,原则上每天只能生成一次吗?

注意:此代码在 Web 应用程序中运行。

(在阅读 Effective Java Item 5:避免创建不必要的对象后开始思考这个问题。)

4

4 回答 4

2
public long seed(int id, long time) {
   return id ^ (time / 86400000L)
}

 have fun
于 2013-09-30T21:05:16.173 回答
1

这个问题归结为生成一个“随机”,但long对于给定的日期和 ID 是一致的。

要提高种子的质量(伪随机性),请hashCode()对每个部分使用包装器:

private static long getSeedForShuffle(int id) {
    return Long.valueOf(TimeUnit.toDays(System.currentTimeMillis())).hashCode() << 32
      + Integer.valueOf(id).hashCode();
}

这里的要点:

  • 用于System.currentTimeMillis()获取“现在”
  • 用于TimeUnit.toDays()将“现在”转换为天数
  • 用于hashCode()创建一致但伪随机(高质量)的种子值
  • 将 int hashCode 值之一左移到 long 的高半部分,因此 hashCode 的所有位都参与结果
  • 避免 using Calendar,这可以说是 JDK 中最糟糕的类

尽管此代码创建了一个 Long 和一个 Integer,但这些对象的重量非常轻,而且 JIT 编译器无论如何都可能内联 hashCode 生成代码。

于 2013-09-30T22:12:29.953 回答
1

我没有编译这个,但可能会给你一个想法。存储午夜的时间戳,然后很容易看到您是否比使用系统时间调用晚 24 小时。

private static final long ONE_DAY = 1000l * 60 * 60 * 24;
private static long midnight = 0;
private static double seed = 0;

private static long getSeedForShuffle(int id)
{
    if (System.currentTimeMillis() - ONE_DAY > midnight) {
      Date date = new Date();
      Calendar cal = MyConstants.UTC_CALENDAR;
      cal.setTime(date);
      int year = cal.get(Calendar.YEAR);
      int month = cal.get(Calendar.MONTH);
      int day = cal.get(Calendar.DAY_OF_MONTH);
      seed = id * 1e8 + year * 1e4 + month * 1e2 + day;
      midnight = new Date(year, month, day).getTime();
    }
    return (long) seed;
}
于 2013-09-29T20:49:38.900 回答
0

假设每一天的长度相同,您不需要分配任何东西(在静态初始化程序中除外,甚至可以消除)。

private static final long MILLIS_PER_DAY = 1000L * 60 * 60 * 24;
private static final long SOME_MIDNIGHT_MILLIS;
static {
    Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    SOME_MIDNIGHT_MILLIS = calendar.getTimeInMillis();
}

private static long getSeedForShuffle(int id) {
    final long millis = System.currentTimeMillis() - SOME_MIDNIGHT_MILLIS;
    long days = millis / MILLIS_PER_DAY;
    return 123456789 * days + id;
}
于 2013-09-29T21:38:25.040 回答