<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>关于 on 庞玉栋个人博客</title><link>https://pangyd.com/tags/%E5%85%B3%E4%BA%8E/</link><description>Recent content in 关于 on 庞玉栋个人博客</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Fri, 17 Nov 2017 21:33:39 +0800</lastBuildDate><atom:link href="https://pangyd.com/tags/%E5%85%B3%E4%BA%8E/index.xml" rel="self" type="application/rss+xml"/><item><title>关于烂代码的一切</title><link>https://pangyd.com/post/171/</link><pubDate>Fri, 17 Nov 2017 21:52:42 +0800</pubDate><guid>https://pangyd.com/post/171/</guid><description>&lt;p>&lt;br>&lt;/p>&lt;div class="content rich" data-reactid=".0.1.0.0.0.1.1.1">&lt;p>&lt;img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='480' height='120'%3E%3Crect width='480' height='120' fill='%230E1012' stroke='%231B1E22'/%3E%3Ctext x='240' y='66' fill='%235C6069' font-family='monospace' font-size='13' text-anchor='middle'%3E%5B%E5%8E%9F%E5%9B%BE%E5%B7%B2%E5%A4%B1%E6%95%88%5D%3C/text%3E%3C/svg%3E">&lt;/p>&lt;p>当程序员经常听到您想要关注ABCD(需求文档/功能设计/架构设计/理解原则)时，编写代码只是将想法翻译成编程语言，这是一种技术内容。&lt;/p>&lt;p>当我听到这种观点的时候，会有一种近似于高寒的蔑视:你是一群傻X，不懂代码质量的重要性等等，这么下去迟早有一天会踩坑。&lt;/p>&lt;p>但几个月后，他们似乎没有进入坑里。随着编程技术的发展，带来了更多的我以前认为是傻X的人加入到程序员这个行业中来。&lt;/p>&lt;p>语言是越来越先进,封装,越来越完美,各种技术帮助程序员提高效率的生产代码,依赖于层的封装,程序员不需要知道的一些技术细节,只要翻译需求的内容逐行是好吗?&lt;/p>&lt;p>许多程序员不知道如何组织他们的代码，如何提高他们的效率，以及底层是如何基于他们在我的头脑中作为一段代码编写的。即使我认为他们写的代码是坨翔，但是从不接触代码的人的视角来看（比如说你的boss），代码编译过了，测试过了，上线运行了一个月都没出问题，你还想要奢求什么？&lt;/p>&lt;p>所以，即使不情愿，也必须承认，时至今日，写代码这件事本身没有那么难了。&lt;/p>&lt;p>许多程序员喜欢简单的东西:简单的函数名，简单的变量名，以及几句话来命名;缩写，缩写，省略，合并或合并。这种类型的代码编写的代码中有很多首字母缩写，没有人知道g /s/gos/ / / MSS，或一串不知道该怎么做的连续调用。&lt;/p>&lt;p>有很多程序员喜欢复杂，各种各样的宏定义，位和位，等等，所以代码似乎不能让它看起来很好。&lt;/p>&lt;p>简单地说，他们的代码是机器，而不是人。&lt;/p>&lt;p>不适当的组织是高级一些不好的代码，程序员写了一些代码，有基本的代码风格，但是对于更大的规模项目控制能力是不够的，不知道代码应该如何解耦，分层，和组织。&lt;/p>&lt;p>这种反模式现象经常出现在复制到项目的代码中;文件中有大量的代码;一个函数堆叠了几十万行;或者一个简单的函数，七到八圈的函数，在一个小的，难以找到的角落里无声地调用一些关键的逻辑。&lt;/p>&lt;p>这种代码的复杂度很高，很难修改，通常会发生崩溃;另一方面，创建代码的人倾向于修改代码，害怕创建代码，他们宁愿一步一步地复杂代码变得更加复杂，不愿意重新组织代码。当你面对几千行的时候，问你为什么不提取所谓的逻辑，他们说:&lt;/p>&lt;p>“这样会多一个类”&lt;/p>&lt;p>相反，如果一个项目的代码很难读，你能说这是糟糕的代码吗?这很难定义，可能不太好，但你能说它很糟糕吗?如果这个项目每次只维护一个人，而且这个人维护得很好，那么它似乎就是“足够的代码”。&lt;/p>&lt;p>许多项目刚刚开始只是一个小项目，而重点仅仅在于代码能够顺利地按时地运行。&lt;/p>&lt;p>过了一段时间后，其他人发现代码写的是问题，而不是理解，不敢移动。需求方又开始催促行，怎么办?我必须小心地改变逻辑，不移动结构，然后在注释中写出来，这样它就很丑，这样我就能理解内部的逻辑并重构它。&lt;/p>&lt;p>在一段时间内，也有类似的需要重用逻辑，只是要意识到代码具有不同特定场景的特殊逻辑，这对于重用非常麻烦。只需复制代码并更改它。问题解决了，问题翻了一倍。&lt;/p>&lt;p>几乎所有的“代码”进化的坏代码，代码不变，使用的代码场景发生了变化，最初的代码不符合新的场景，所以它变成了一个糟糕的代码。&lt;/p>&lt;p>从技术上讲，重构复杂代码时，要做三件事:理解旧代码，分解旧代码，构建新代码。要重构的旧代码通常很难理解;模块间的过度耦合导致了影响对整个身体的影响。旧代码不容易测试，不能保证新代码的正确性。&lt;/p>&lt;p>还有一个核心问题，重构的复杂性并不依赖于代码的复杂性。例如，如果你有1000行代码，重构需要1个小时，所以重构5000行代码需要2到3天的时间。重构一个失去控制的项目通常比重写它的效率要低。&lt;/p>&lt;p>在重构方面，重构也是一件非常困难的事情:很难直接从中获益，而且很难量化。这里有一个有趣的现象，几乎所有关于重构的书都有一个独立的章节，关于“如何向老板解释重构的需要”。&lt;/p>&lt;p>重构后你能提高多少效率?可以减少多少风险?很难说，糟糕的代码本身并不是一个简单的标准化的东西。&lt;/p>&lt;/div></description></item><item><title>转载自【Java编程精选】关于 Java 你不知道的十件事</title><link>https://pangyd.com/post/68-java-java/</link><pubDate>Sat, 19 Aug 2017 20:49:33 +0800</pubDate><guid>https://pangyd.com/post/68-java-java/</guid><description>&lt;p>&lt;span>作为Java 控&lt;span>，&lt;/span>&lt;/span>&lt;span>&lt;span>我们总是对&lt;/span>&lt;span>不太可能直接使用&lt;/span>&lt;span>，&lt;/span>&lt;span>但&lt;/span>&lt;span>能使我们更&lt;/span>&lt;/span>&lt;span>&lt;span>了解&lt;/span>&amp;nbsp;Java 和 Java 虚拟机（Java Virtual Machine，JVM） 的晦涩细节感兴趣。这也是我将 Lukas Eder 在&amp;nbsp;&lt;/span>jooq.org&lt;span>&amp;nbsp;上写的这篇&lt;/span>文章&lt;span>发布出来的原因。&lt;/span>&lt;/p>&lt;p>&lt;span>你在Java发布的时候就开始使用了吗？还&lt;/span>记得那时它叫“Oak”，面向对象也 （Object Oriented， OO ）还是个热门话题，C++ 程序员们觉得 Java 完全没机会成功&lt;span>，Applet的出现也是一件新鲜大事？&lt;/span>&lt;/p>&lt;p>&lt;span>我打赌下文中&lt;/span>至少一半的内容你都不知道。让我们来看看这些令人惊喜的 Java 细节吧。&lt;/p>&lt;h2>1. 受检异常（checked exception）这件事是不存在的&lt;/h2>&lt;p>是这样的，JVM 完全不知道这件事，&lt;span>都是Java语言做的[只有Java语言这么干]。&lt;/span>&lt;/p>&lt;p>现在，&lt;span>异常检查&lt;/span>被公认为是个错误，正如 Brue Eckel 在布拉格的 GeeCON 大会上的闭幕词中所说， Java 后的其他语言&lt;span>都不再使用异常检查了，&lt;/span>就连 Java 8 都不愿在新的 Stream API 中使用它了（当你在 lambda 表达式中使用 IO 或者 JDBC 时，是很痛苦的）。&lt;/p>&lt;p>你想要&lt;span>证明 JVM 不知道异常检查这件事&lt;/span>吗？尝试以下代码：&lt;/p>&lt;p>&lt;img data-s="300,640" data-type="png" data-src="https://pangyd.com/uploads/2017/08/74c10f869f038762.jpg" class="" data-ratio="0.3784246575342466" data-w="584" src="https://pangyd.com/uploads/2017/08/74c10f869f038762.jpg" data-fail="0">&lt;/p>&lt;p>&lt;span>这个不仅会编译，还会抛出 SQLException&lt;span>&amp;nbsp;，你&lt;/span>&lt;/span>&lt;span>甚至&lt;/span>&lt;span>&lt;span>不&lt;/span>需要 Lombok 的&amp;nbsp;&lt;/span>@SneakyThrows&lt;span>&amp;nbsp;标签。&lt;/span>&lt;/p>&lt;p>更多详情请参考这篇文章，或者 Stack Overflow 上的这篇文章。&lt;/p>&lt;h2>2. 可以使用不同的返回值类型来重载方法&lt;/h2>&lt;p>以下代码是编译不过的，对吧？&lt;/p>&lt;p>&lt;img data-s="300,640" data-type="png" data-src="https://pangyd.com/uploads/2017/08/74c10f869f038762.jpg" class="" data-ratio="0.14492753623188406" data-w="483" src="https://pangyd.com/uploads/2017/08/74c10f869f038762.jpg" data-fail="0">&lt;/p></description></item><item><title>关于 JCombobox</title><link>https://pangyd.com/post/47-jcombobox/</link><pubDate>Wed, 09 Aug 2017 21:42:14 +0800</pubDate><guid>https://pangyd.com/post/47-jcombobox/</guid><description>&lt;p>&lt;span>构造函数&lt;/span>&lt;span>&amp;nbsp;&lt;/span>&lt;/p>&lt;span>JComboBox()&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 创建具有默认数据模型的 JComboBox。&amp;nbsp;&lt;/span>&lt;br>&lt;span>JComboBox(ComboBoxModel aModel)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 创建一个 JComboBox，其项取自现有的 ComboBoxModel 中。&amp;nbsp;&lt;/span>&lt;br>&lt;span>JComboBox(Object[] items)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 创建包含指定数组中的元素的 JComboBox。&amp;nbsp;&lt;/span>&lt;br>&lt;span>JComboBox(Vector&amp;lt;?&amp;gt; items)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 创建包含指定 Vector 中的元素的 JComboBox。&amp;nbsp;&lt;/span>&lt;br>&lt;br>&lt;span>常用方法&amp;nbsp;&lt;/span>&lt;br>&lt;span>addActionListener(ActionListener l)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 添加 ActionListener。&amp;nbsp;&lt;/span>&lt;br>&lt;span>addItem(Object anObject)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 为项列表添加项。&amp;nbsp;&lt;/span>&lt;br>&lt;span>addItemListener(ItemListener aListener)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 添加 ItemListener。&amp;nbsp;&lt;/span>&lt;br>&lt;span>configureEditor(ComboBoxEditor anEditor, Object anItem)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 利用指定项初始化编辑器。&amp;nbsp;&lt;/span>&lt;br>&lt;span>getEditor()&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 返回用于绘制和编辑 JComboBox 字段中所选项的编辑器。&amp;nbsp;&lt;/span>&lt;br>&lt;span>getItemAt(int index)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 返回指定索引处的列表项。&amp;nbsp;&lt;/span>&lt;br>&lt;span>getItemCount()&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 返回列表中的项数。&amp;nbsp;&lt;/span>&lt;br>&lt;span>getModel()&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 返回 JComboBox 当前使用的数据模型。&amp;nbsp;&lt;/span>&lt;br>&lt;span>getRenderer()&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 返回用于显示 JComboBox 字段中所选项的渲染器。&amp;nbsp;&lt;/span>&lt;br>&lt;span>getSelectedIndex()&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 返回列表中与给定项匹配的第一个选项。&amp;nbsp;&lt;/span>&lt;br>&lt;span>getSelectedItem()&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 返回当前所选项。&amp;nbsp;&lt;/span>&lt;br>&lt;span>insertItemAt(Object anObject, int index)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在项列表中的给定索引处插入项。&amp;nbsp;&lt;/span>&lt;br>&lt;span>isEditable()&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 如果 JComboBox 可编辑，则返回 true。&amp;nbsp;&lt;/span>&lt;br>&lt;span>removeAllItems()&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 从项列表中移除所有项。&amp;nbsp;&lt;/span>&lt;br>&lt;span>removeItem(Object anObject)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 从项列表中移除项。&amp;nbsp;&lt;/span>&lt;br>&lt;span>removeItemAt(int anIndex)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 移除 anIndex 处的项。&amp;nbsp;&lt;/span>&lt;br>&lt;span>setModel(ComboBoxModel aModel)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 设置 JComboBox 用于获取项列表的数据模型。&amp;nbsp;&lt;/span>&lt;br>&lt;span>setRenderer(ListCellRenderer aRenderer)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 设置渲染器，该渲染器用于绘制列表项和从 JComboBox 字段的列表中选择的项。&amp;nbsp;&lt;/span>&lt;br>&lt;span>setSelectedIndex(int anIndex)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 选择索引 anIndex 处的项。&amp;nbsp;&lt;/span>&lt;br>&lt;span>setSelectedItem(Object anObject)&amp;nbsp;&lt;/span>&lt;br>&lt;span>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 将组合框显示区域中所选项设置为参数中的对象&lt;/span></description></item><item><title>关于Class.forName(“com.mysql.jdbc.Driver”)</title><link>https://pangyd.com/post/30-class-forname-com-mysql-jdbc-driver/</link><pubDate>Thu, 03 Aug 2017 17:14:46 +0800</pubDate><guid>https://pangyd.com/post/30-class-forname-com-mysql-jdbc-driver/</guid><description>&lt;p>传统的使用jdbc来访问数据库的流程为：&lt;br> Class.forName(“com.mysql.jdbc.Driver”);&lt;br> String url = “jdbc:mysql://localhost:3306/test?user=root&amp;amp;password=123456″;&lt;br> Connection con = DriverManager.getConnection(url);&lt;br> Statement statement = con.createStatement();&lt;/p>&lt;p>最开始使用的时候，不明白为什么首先要加载一个驱动类，之后就可以取得了Connection了，很好奇DriverManager是怎么获得那个驱动类的信息，后来看了下com.mysql.jdbc.Driver这个类的源代码，豁然开朗了。原来在com.mysql.jdbc.Driver类中有这么一段静态初始化代码：&lt;br> static {&lt;br> try {&lt;br> java.sql.DriverManager.registerDriver(new Driver());&lt;br> } catch (SQLException E) {&lt;br> throw new RuntimeException(“Can’t register driver!”);&lt;br> }&lt;br> }&lt;br> 也就是，在Class.forName加载完驱动类，开始执行静态初始化代码时，会自动新建一个Driver的对象，并调用DriverManager.registerDriver把自己注册到DriverManager中去。&lt;br>&lt;br>&lt;strong>ps1:&lt;/strong> Class.forName(String) 与ClassLoader.loadClass(String)的区别&lt;br> Class.forName(String): 加载类，并且执行类初始化；可以通过Class.forName(String, boolean, ClassLoader)第二个参数来仅仅加载类不执行初始化；&lt;br> ClassLoader.loadClass(String): 仅仅加载类，不执行类初始化；&lt;/p>&lt;p>&lt;strong>ps2:&lt;/strong> 有时会看到这种用法：&lt;br> Class.forName(“com.mysql.jdbc.Driver”).newInstance();&lt;br> 这是没有必要的，正如前述，静态初始化已经new了一个Driver的对象，注册到DriverManager中去，在此再建立一个Driver对象则是完全没有必要的，浪费空间。&lt;/p>&lt;p>&lt;strong>ps3:&lt;/strong> 结合ps1，Class.forName(“com.mysql.jdbc.Driver”);相当于：&lt;br> ClassLoader loader = Thread.currentThread().getContextClassLoader();&lt;br> Class cls = loader.loadClass(“com.mysql.jdbc.Driver”);&lt;br> cls.newInstance();&lt;br> 这种方法的问题同ps2, 浪费了一个Driver对象；&lt;/p>&lt;p>&lt;strong>ps4:&lt;/strong> 在java 6中，引入了service provider的概念，即可以在配置文件中配置service（可能是一个interface或者abstract class）的provider（即service的实现类）。配置路径是：/META-INF/services/下面。详细信息见：https://docs.oracle.com/javase/6/docs/technotes/guides/jar/jar.html#Service%20Provider&lt;br> 而java.sql.DriverManager也添加了对此的支持，因此，在JDK6中，DriverManager的查找Driver的范围为：&lt;br> 1）system property “jdbc.drivers” 中配置的Driver值；&lt;br> 2）用户调用Class.forName()注册的Driver&lt;br> 3）service provider配置文件java.sql.Driver中配置的Driver值。&lt;br> 因此，在jdk6中，其实是可以不用调用Class.forName来加载mysql驱动的，因为mysql的驱动程序jar包中已经包含了java.sql.Driver配置文件，并在文件中添加了com.mysql.jdbc.Driver.但在JDK6之前版本，还是要调用这个方法。&lt;/p></description></item></channel></rss>