Java小问题总结第一期

前言:

        最近完成了一个多功能时钟的编写,其中涉及到了一些形如exe文件如何读写外部配置文件,jre体积太大的小问题。虽然后面都一一解决了,不过我觉得有必要写上来,为可能遇到类似问题的程序猿们提供一些思路(* ̄︶ ̄):

问题1:jar/exe文件读写外部配置文件

        听起来不是很难,但我之前只学会了如何在项目中读取配置文件,比如像这样—— 

File file3 = new File(Test.class.getResource("file3.txt").getFile());

RandomAccessFile file4=new RandomAccessFile(new File(Test.class.getResource("file4.txt").toURI,"rw"));//示范

        他人的博客里有这么一句话:至于getResouce()方法的参数,你以class为出发点,再结合相对路径的概念,就可以准确地定位资源文件了,这句话准确的概括出了getResource()的用法,所以我不多说,感兴趣的可以看看:java中Class.getResource用法(用于配置文件的读取) - 路修远而求索 - 博客园

        到后面开始着手于这个小程序后,我才发现在eclipse中的项目中读取配置文件和在实际生产环境中读写配置文件完全是两回事,因为在你将项目打包成jar后,里面的文件夹层次完全乱套了——

         原来的src文件夹直接变没了,bin文件夹也只剩下其子文件夹,而且配置文件要求具有一定的灵活性,直接打包在jar里面未免不太妥当。所以按照以前的getResource()方法,明显是行不通的,所以我找到了可行的方法,也就是通过寻找jar/exe文件,进而找到同一个文件夹内的配置文件。

String path = System.getProperty("user.dir") + "\\XXX.properties"

        其中,System.getProperty("user.dir")会寻找调用它的程序的当前路径,再与配置文件名拼接,这样就使得无论jar包移动到哪个位置,都可以使用与jar包在同一个目录下的XXX.properties配置文件。同时也保证了配置文件的灵活性,没有把配置文件包死在jar包中。

附如何修改配置文件:java 更新properties配置文件 - gavinwangxj - 博客园

问题2:jar打包成exe遇到的问题

        本人的小程序中,有一个爬取百度新闻的功能,在使用exe4j打包生成exe文件后运行时,error.log中出现了个很不可思议的异常/error——java.lang.NoClassDefFoundError

Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: org/apache/hc/core5/http/ClassicHttpRequest
	at Quicky_Clock.MainFrame.initialize(MainFrame.java:126)
	at Quicky_Clock.MainFrame.<init>(MainFrame.java:31)
	at Quicky_Clock.MainFrame$1.run(MainFrame.java:23)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.lang.ClassNotFoundException: org.apache.hc.core5.http.ClassicHttpRequest
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
	... 16 more

        提示是Caused by java.lang.ClassNotFoundException,通过error.log我初步判断是所谓的“找不到一个叫org.apache.hc.core5.http.ClassicHttpRequest的类”的异常,但是神奇的地方在于,同样的代码在eclipse中运行毫无问题,这就证明不是代码、导包或者包版本的问题,而可能是导入的httpcore5包调用有问题。

        苦思冥想了许久,也查阅了相关资料,没有什么头绪,直到我翻到了一篇救命的CSDN:

​​​​​​使用exe4j把jar转换成exe文件时,报错java.lang.NoClassDefFoundError: org/eclipse/swt/widgets/Composite_jia611的专栏-CSDN博客

        不想看的话,直接上文章重点:

        如果你eclipse export时选择 Package required libraries into generated jar,那么在exe4j中就要选  org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader 作为main class (注意这是exe4j里的设置,eclipse导出时还是选你原来的main class)。

        如果你export时选择 Copy required libraries into a sub-folder next to the generated jar
要在exe4j, java invocation中将所有jar添加入class path,这时可以选原来程序里的main class。
我的理解是这个JarRsrcLoader类就是专门用来调用jar包中的各种外部jar包,如果直接从main class开始,这个类的功能就丧失了

示例:

        这让我深刻认识到,开发环境和生产环境真不能当做一回事(eclipse真的是又当爹又当妈),也好,毕竟吃一堑长一智,以后不会怕这种问题了O(∩_∩)O哈哈~

问题3:jre太大了怎么办

        这个问题很好解决,也必须解决。毕竟不会有用户为了下载个代码只有十几k的多功能时钟,而被捆绑安装上他们根本不会真正用到的,又占据100-200m的“庞大的”jre。但是可惜Oracle压根没有提供一种可以帮程序员精简程序所需的jre的工具,所以只能自己动手了:

第一步:精简jre目录

        很简单,删除那些除了bin和lib的其他东西

第二步:精简bin目录

        这个我没有深入研究,不过下面这篇文章讲的倒是没啥毛病,可以借鉴一下

        ​​Java 精简Jre_水瓶座鬼才的博客-CSDN博客_java jre

第三步:精简lib目录

        打开jre下的lib目录,你就会发现其中占据空间最大的就是rt.jar,所以主要的工作应该是放在它身上,下面是几个主要的包的作用——

        rt.jar : 运行时包

        dt.jar: dt.jar是关于运行环境的类库

        tools.jar: tools.jar是工具类库,编译和运行需要的都是toos.jar里面的类分别是sun.tools.java. ; sun.tols.javac.;

        ant-javafx.jar: javaFX包的ant工具

        charsets.jar: Java 字符集,这个类库中包含 Java 所有支持字符集的字符

        cldrdata.jar: http://cldr.unicode.org/ CLDR - Unicode Common Locale Data Repository

        我的偷懒式做法就是将rt.jar的后缀改为zip(jar本质也是特殊的zip文件),用360压缩打开后,根据你的项目来直接删除那些根本用不到的类,比如说我的多功能时钟不包含音乐功能,那么我可以直接删除javax.sound.*和java.applet类,或者说我不需要与数据库进行交互,那我可以直接删除java.sql.* ... ...通过这样一顿操作,可以让jre变成只有原来的1/4,虽然还是很大,不过好很多了。

        在加上对bin目录的精简,可以让这个程序的jre大小变成原来的1/6——

        

        别人的正常做法:

        Java 精简Jre_水瓶座鬼才的博客-CSDN博客_java jre

        全篇完

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值