使用实用程序生成Java代码,使我的项目更加简洁。好主意?
我正在从事的项目需要我编写大量重复的代码。例如,如果我想在代码中加载一个名为“logo.png”的图像文件,我会这样写: 位图图像使用实用程序生成Java代码,使我的项目更加简洁。好主意?,java,android,code-generation,Java,Android,Code Generation,我正在从事的项目需要我编写大量重复的代码。例如,如果我想在代码中加载一个名为“logo.png”的图像文件,我会这样写: 位图图像 ... // Init logoImage = load("logo.png") ... // Usage logoImage.draw(0, 0); .. // Cleanup logoImage.release(); 必须编写此代码才能使用每个新图像是一件痛苦的事情,包括必须指定logoImage应加载文件“logo.png” 由于我正在开发一款Java
...
// Init
logoImage = load("logo.png")
...
// Usage
logoImage.draw(0, 0);
..
// Cleanup
logoImage.release();
必须编写此代码才能使用每个新图像是一件痛苦的事情,包括必须指定logoImage应加载文件“logo.png”
由于我正在开发一款Java Android游戏,而且图像在内部循环中被大量使用,所以我真的希望避免一些缓慢的事情,比如进行虚拟函数调用,以及在可以避免的情况下访问数组/地图/对象字段。从AndroidAPI(生成的R类)复制一个想法,我想我可以在编译之前运行一个实用程序,为我生成一些重复的代码。例如,项目文件中的实际代码将减少为:
logoImage.draw(0, 0);
使用一些命令行工具(例如grep、sed),我可以查找“Image.draw(…)”的每个实例,然后自动生成其他必需的代码,即加载/释放文件.png和声明“Bitmap logoImage”的代码这个代码可以被添加到一个新的类中,或者我可以在我的代码中添加占位符,告诉代码生成器在哪里插入生成的代码
要显示新图像,我只需将图像文件复制到正确的目录并添加一行代码即可。非常简单。这避免了创建图像数组、定义带标签的int常量以引用数组以及必须指定要加载的文件名等方法
这真的是一个坏主意吗?这似乎有点像黑客,但我看不到更简单的方法,它似乎彻底清理了我的代码。有没有标准的工具来完成这种简单的代码生成(即,该工具不需要理解代码的含义)其他人这样做是为了弥补语言功能吗?避免代码生成。这通常会使代码难以维护 在你的情况下,你为什么不:
public class ImageUtils {
public static void drawAndRelease(String name) {
logoImage = load(name)
logoImage.draw(0, 0);
logoImage.release();
}
}
然后打电话:
ImageUtils.drawAndRelease("logo.png");
如果这些方法之间有更多的代码,那么它们就是原子方法,在使用代码生成时,您将不知道将它们放在何处。有几种方法:
EclipseCode2Code,您可以使用模板语言(如FreeMarker、groovy等)在模板中编写代码
用于Android的eclipse sqLite插件自动生成sqLite代码
MotoDevStudio4android有代码片段,你可以使用它。我支持Bozho关于避免代码生成的回答,但如果你必须编写可重复的代码片段,任何好的IDE通常都有一些内置的支持,用于指定你自己的带有变量的代码片段和所有内容。IntelliJ IDEA有这个功能,它被称为实时模板。我猜Eclipse和NetBeans都有类似的功能。您将复杂性转移到代码生成上,而它(生成)并不是微不足道的,可能有缺陷。
代码更难阅读和维护。一些清晰的设计和编码规则在这里更有用。对于这样的事情使用代码生成是个坏主意。(依我看,代码生成应该保留在需要生成大量代码的情况下,而这听起来不像那种情况。) 如果您当前解决方案中的样板代码与您有关,那么更好的解决方案(比代码生成)是实现图像注册表抽象;例如
public class ImageRegistry {
private Map<String, Image> map = new HashMap<String, Image>();
public synchronized Image getImage(String filename) {
Image image = map.get(filename);
if (image == null) {
image = load(filename);
map.put(filename, image);
}
return image;
}
public synchronized void shutdown() {
for (Image image : map.valueSet()) {
image.release();
}
map.clear(); // probably redundant ...
}
}
删除所有load
调用,并用对registry.shutdown()的单个调用替换所有release
调用
编辑以回应OP的以下评论:
…但我提到我正在为手机编写一个游戏。每次我绘制精灵时进行哈希图查找都会降低性能
啊…我从另一条线索记得你
你(再一次)在没有任何实际性能测量依据的情况下对性能进行假设。具体来说,你假设HashMap查找将过于昂贵。我的直觉是,查找所需的时间只占很小的百分比(<10%)绘制图像所需的时间。此时,图像已接近用户无法察觉的程度
如果您的测量结果(或直觉)告诉您hashmap查找过于昂贵,那么编写以下内容只是一个微不足道的修改:
Image=registry.getImage(“logo.png”);
而(…){
...
图像绘制(0,0);
}
例如,Google甚至建议不要在内部循环中使用迭代器,因为这样会在迭代器对象被释放时触发GC
这是不相关和不准确的
使用字符串键的HashMap查找不会生成垃圾。永远不会
在内部循环中使用迭代器不会“在迭代器对象被释放时导致GC触发”。在Java中,您不会释放对象。这是C/C++的想法
在内部循环中实例化迭代器不会对对象执行new
操作,但是只有当new
操作达到内存阈值时,GC才会触发。这种情况只是偶尔发生的
此外,在您的示例中,编写“file_that_not_exist.png”不会被视为编译时错误
您的原始解决方案或代码生成方法都不能为丢失的文件提供编译时错误。如果您愿意为您生成代码,那么就开始吧。我会确保您的代码生成器经过完整的单元测试,然后再信任它编辑您的源代码文件。。。“如果你愿意为自己生成代码,那就去吧”我想我也在问“这种方法有多普遍”?我更愿意为此使用一种语言功能,但我不知道Java中有这种功能。“我会确保你的代码生成器接受一整套单元测试”
registry.getImage("logo.png").draw(0, 0);