数组作为 switch case 的替代品的性能
Performance of arrays as alternative to switch cases
通常,在我在学校遇到的问题中,有些问题希望我们使用 switch cases。虽然为了更短的代码,我总是使用数组作为这种问题的替代方法。
因此,使用 Switch-Statement 的解决方案如下所示:
String day;
int dayNum = n%7; //n is an input
switch(dayNum){
case 0:
day = "Sunday";
break;
case 1:
day = "Monday";
break;
case 2:
day = "Tuesday";
break;
case 3:
day = "Wednesday";
break;
case 4:
day = "Thursday";
break;
case 5:
day = "Friday";
break;
case 6:
day = "Saturday";
break;
}
System.out.println("Today is " + day);
用数组替代的解决方案如下所示:
int dayNum = n%7; //n is an input
String[] day = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
System.out.println("Today is " + day[dayNum]);
第二个例子是我通常喜欢使用的那种代码。
我想问的是,这两种解决方案在内存和时间复杂度方面有何不同?
你写的代码只是开关使用不当。
当满足其中一项(或最好同时满足两项)时,开关就很棒:
- 您触发的值不是连续的(即
case 384:
,然后是 case 30491:
,等等。简单的例子是为某个命令打开字符串时。
- 您要做的是一堆代码(相对于返回单个结果,如此处所示)。
尽管如此,您还以相当复杂的方式编写了 case 块。如果你有一个单独的方法,你可以写:
switch (foo) {
case 0: return "Sunday";
case 1: return "Monday";
}
还有(new in..java14?),你也可以这么写:
String dayName = switch(foo) {
case 0 -> "Sunday";
case 1 -> "Monday";
default -> throw new IllegalArgumentException("Unknown day");
};
最后,这段代码不应该存在。因为 java.time.DayOfWeek
已经存在。你彻底重新发明了轮子。
性能
当谈论 7 个元素时,它并不重要。其他因素占主导地位,就这么简单。
作为一般原则(直到数百甚至数千,见脚注!),你的基于数组的代码在你写的时候是线性的原因是唯一 因为 java 不会(目前;未来的 java 更改正在进行中,可能会改变这一点)意识到 'makes' 带有日期名称的字符串数组可以执行一次JVM 引导的生命周期,再也不会;换句话说,这段代码在幕后编译为创建一个具有 7 个槽的新字符串数组,然后将 7 个常量分配给槽(这些常量是对字符串的引用, 是 计算“每个 VM 生命周期一次”)。
如果将该数组移动到静态字段中,那将消失,并且它们都是 O(1)
性能(相同 'speed' 无论您有 7 天还是 700 万天),因为它们两者都只进行一次查找。没有循环。
重要性能脚注:计算机非常复杂,并且什么都没有就像冯·诺依曼模型。因此,根据常识预测代码的性能通常会使您大错特错。因此,需要牢记 3 条重要规则:
按照全世界的程序员 java 编写代码的方式编写代码,并保持灵活性。 如果 出现性能问题,您可能需要更改应用的相关部分。如果您的代码灵活,这会更容易。 你读到的大多数关于性能的经验法则都会降低你的代码的灵活性,因此很糟糕! - 此外,JVM 优化代码,并且基本上通过成为一个巨大的模式匹配机器来做到这一点,检测它知道如何 运行 的模式。制作此模式匹配优化机器的程序员倾向于编写 java 代码中常用的模式。因此,惯用的 java 代码在实践中往往很快。
没有人可以只看代码就知道它在现实生活中的表现如何,因为它太复杂了。不要相信我的话; 编写 VM 的工程师一直都这么说。如果他们想不通,你就没有任何机会。因此,在考虑让代码性能想法决定您编写代码的方式之前,需要 分析器报告或 JMH 计时结果。请参阅上面的规则:没有这个,最好、最快的代码就是最干净、最灵活、最易于阅读的代码。
唯一的例外是算法复杂性(大 O 表示法)。这是一个复杂的主题(通常是大学水平的信息学和非常重的数学),远远超出了 SO 的答案,但如果您想深入研究,可以找到大量的在线资源。但请注意,大 O 因素通常不会在您获得大量数据之前,请开始控制。例如,在这种情况下,从技术上讲,您的基于数组的代码是 O(n)
(因为您在代码中创建数组,每次 运行 它),而开关是 O(1)
,但是鉴于这里的 n 是 7,那是无关紧要的。在您获得数百个项目之前,它可能不会变得相关。
通常,在我在学校遇到的问题中,有些问题希望我们使用 switch cases。虽然为了更短的代码,我总是使用数组作为这种问题的替代方法。
因此,使用 Switch-Statement 的解决方案如下所示:
String day;
int dayNum = n%7; //n is an input
switch(dayNum){
case 0:
day = "Sunday";
break;
case 1:
day = "Monday";
break;
case 2:
day = "Tuesday";
break;
case 3:
day = "Wednesday";
break;
case 4:
day = "Thursday";
break;
case 5:
day = "Friday";
break;
case 6:
day = "Saturday";
break;
}
System.out.println("Today is " + day);
用数组替代的解决方案如下所示:
int dayNum = n%7; //n is an input
String[] day = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
System.out.println("Today is " + day[dayNum]);
第二个例子是我通常喜欢使用的那种代码。
我想问的是,这两种解决方案在内存和时间复杂度方面有何不同?
你写的代码只是开关使用不当。
当满足其中一项(或最好同时满足两项)时,开关就很棒:
- 您触发的值不是连续的(即
case 384:
,然后是case 30491:
,等等。简单的例子是为某个命令打开字符串时。 - 您要做的是一堆代码(相对于返回单个结果,如此处所示)。
尽管如此,您还以相当复杂的方式编写了 case 块。如果你有一个单独的方法,你可以写:
switch (foo) {
case 0: return "Sunday";
case 1: return "Monday";
}
还有(new in..java14?),你也可以这么写:
String dayName = switch(foo) {
case 0 -> "Sunday";
case 1 -> "Monday";
default -> throw new IllegalArgumentException("Unknown day");
};
最后,这段代码不应该存在。因为 java.time.DayOfWeek
已经存在。你彻底重新发明了轮子。
性能
当谈论 7 个元素时,它并不重要。其他因素占主导地位,就这么简单。
作为一般原则(直到数百甚至数千,见脚注!),你的基于数组的代码在你写的时候是线性的原因是唯一 因为 java 不会(目前;未来的 java 更改正在进行中,可能会改变这一点)意识到 'makes' 带有日期名称的字符串数组可以执行一次JVM 引导的生命周期,再也不会;换句话说,这段代码在幕后编译为创建一个具有 7 个槽的新字符串数组,然后将 7 个常量分配给槽(这些常量是对字符串的引用, 是 计算“每个 VM 生命周期一次”)。
如果将该数组移动到静态字段中,那将消失,并且它们都是 O(1)
性能(相同 'speed' 无论您有 7 天还是 700 万天),因为它们两者都只进行一次查找。没有循环。
重要性能脚注:计算机非常复杂,并且什么都没有就像冯·诺依曼模型。因此,根据常识预测代码的性能通常会使您大错特错。因此,需要牢记 3 条重要规则:
按照全世界的程序员 java 编写代码的方式编写代码,并保持灵活性。 如果 出现性能问题,您可能需要更改应用的相关部分。如果您的代码灵活,这会更容易。 你读到的大多数关于性能的经验法则都会降低你的代码的灵活性,因此很糟糕! - 此外,JVM 优化代码,并且基本上通过成为一个巨大的模式匹配机器来做到这一点,检测它知道如何 运行 的模式。制作此模式匹配优化机器的程序员倾向于编写 java 代码中常用的模式。因此,惯用的 java 代码在实践中往往很快。
没有人可以只看代码就知道它在现实生活中的表现如何,因为它太复杂了。不要相信我的话; 编写 VM 的工程师一直都这么说。如果他们想不通,你就没有任何机会。因此,在考虑让代码性能想法决定您编写代码的方式之前,需要 分析器报告或 JMH 计时结果。请参阅上面的规则:没有这个,最好、最快的代码就是最干净、最灵活、最易于阅读的代码。
唯一的例外是算法复杂性(大 O 表示法)。这是一个复杂的主题(通常是大学水平的信息学和非常重的数学),远远超出了 SO 的答案,但如果您想深入研究,可以找到大量的在线资源。但请注意,大 O 因素通常不会在您获得大量数据之前,请开始控制。例如,在这种情况下,从技术上讲,您的基于数组的代码是
O(n)
(因为您在代码中创建数组,每次 运行 它),而开关是O(1)
,但是鉴于这里的 n 是 7,那是无关紧要的。在您获得数百个项目之前,它可能不会变得相关。