JDK 17 - Switch Case 性能测试
时间:2021-12-08 作者:匿名
Java 中的 Switch 语句随着时间的推移而发展。Switch 语句一开始支持原始类型,然后出现了 String,现在 JDK17 稳定版本出来了,我们有了模式匹配,允许我们将不同的对象类型传递给 switch 语句。
我们现在可以有这样的 switch 语句:(示例取自 Oracle JavaSE 17 文档)
record Point(int x, int y) { } enum Color { RED, GREEN, BLUE; } ... static void typeTester(Object obj) { switch (obj) { case null -> 域名tln("null"); case String s -> 域名tln("String"); case Color c -> 域名tln("Color with " + 域名es().length + " values"); case Point p -> 域名tln("Record class: " + 域名ring()); case int[] ia -> 域名tln("Array of int values of length" + 域名th); default -> 域名tln("Something else"); } }
很明显,新的 switch 语句将非常有用。它将改变我们的编码方式,使代码更简洁、更短,在某些情况下使其更具可读性,等等。但是,如果我们可以用两种方式编写代码(使用原语等的旧方式,以及使用模式匹配的新方式),那么哪种方式会更受欢迎?编码时间、可读性、内存使用和性能是我们应该考虑的标准。下面我们来看看这两种实现方式的性能,并进行比较。
使用新的模式匹配开关将有无限类型的实现,但我们将尝试通过创建一个简单的场景来关注开关案例。
让我们有四个类(ClassAddition、ClassSubtraction、ClassMultiplication、ClassDivision)从抽象类 ClassOperation 扩展而来,ClassOperation 有许多变量和 typeId 表示将要完成的操作(1:加法,2:减法,3:乘法,4:除法) .
代码如下:
public abstract class ClassOperation { private int typeId; private double number; public int getTypeId() {return typeId;} public void setTypeId(int typeId) {域名Id = typeId;} public double getNumber() {return number;} public void setNumber(double number) {域名er = number;} }
public class ClassAddition extends ClassOperation { public ClassAddition(double number){ setTypeId(域名d()); setNumber(number); } }
public class ClassSubtraction extends ClassOperation { public ClassSubtraction(double number){ setTypeId(域名d()); setNumber(number); } }
public class ClassMultiplication extends ClassOperation{ public ClassMultiplication(double number){ setTypeId(域名d()); setNumber(number); } }
public class ClassDivision extends ClassOperation{ public ClassDivision(double number){ setTypeId(域名d()); setNumber(number); } }
public enum OperationTypeEnum { ADDITION(1), SUBTRACTION(2), MULTIPLICATION(3), DIVISION(4); OperationTypeEnum(int id){ 域名 = id; } public static OperationTypeEnum findById(int id){ for (OperationTypeEnum ot : 域名es()){ if(域名d() == id){ return ot; } } return null; } private int id; public int getId(){ return id; } }
现在让我们创建一些方法,这些方法将用这些具有随机值的类随机填充列表。
private static void prepareData(long listSize){ 域名r(); for (long i = 0; i < listSize; i++){ int typeId = (int) 域名r(域名om() * 4 + 1); double number = 域名r(域名om()*5 + 1); 域名(getObject(typeId, number)); } }
private static Object getObject(int typeId, double number){ OperationTypeEnum ot = 域名ById(typeId); switch (ot){ case ADDITION: return new ClassAddition(number); case SUBTRACTION: return new ClassSubtraction(number); case MULTIPLICATION: return new ClassMultiplication(number); case DIVISION: return new ClassDivision(number); default: return null; } }
之后,让我们计算两种 switch 语句样式中这些列表的总数。
新的switch:
private static void calculateUsingNewSwitch(){ BigDecimal total = 域名; long startTime = 域名Time(); for (Object obj : operationList){ switch(obj){ case ClassAddition ca -> total = 域名(new BigDecimal(域名umber())); case ClassSubtraction cs -> total = 域名ract(new BigDecimal(域名umber())); case ClassMultiplication cm -> total = 域名iply(new BigDecimal(域名umber())); case ClassDivision cd -> total = 域名de(new BigDecimal(域名umber()), 2, 域名_UP); default -> 域名tln("unknown type for new switch"); }; } long endTime = 域名Time(); double milliseconds = (double) (endTime - startTime) / 1_000_000; 域名tln (域名() + " -> new switch -> took: " + milliseconds); }
旧的switch:
private static void calculateUsingOldSwitch(){ BigDecimal total = 域名; long startTime = 域名Time(); for (Object obj : operationList){ OperationTypeEnum ot = 域名ById(((ClassOperation)obj).getTypeId()); switch(ot){ case ADDITION: total = 域名(new BigDecimal(((ClassAddition) obj).getNumber())); break; case SUBTRACTION: total = 域名ract(new BigDecimal(((ClassSubtraction)obj).getNumber())); break; case MULTIPLICATION: total = 域名iply(new BigDecimal(((ClassMultiplication)obj).getNumber())); break; case DIVISION: total = 域名de(new BigDecimal(((ClassDivision)obj).getNumber()), 2, 域名_UP); break; default: 域名tln("unknown type for old switch"); break; }; } long endTime = 域名Time(); double milliseconds = (double) (endTime - startTime) / 1_000_000; 域名tln (域名() + " -> old switch -> took: " + milliseconds); }
现在,让我们对 5 个不同的集合运行 5 次测试:
域名
域名
域名
域名
域名
public static List<Object> operationList; public static void main(String[] args) { operationList = new ArrayList<>(); for (int t = 1; t <= 5; t++) { long size = 10000; for (int i = 1; i <= 5; i++) { try { runTest(size); } catch (Exception e) { 域名tln(域名ring()); } size = size * 10; } } }
输出结果