`
chendang1314
  • 浏览: 104023 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

编程随想

    博客分类:
  • java
阅读更多
只有两样东西可能是无限的:宇宙和人类的愚蠢。但是对于前者我不太确定。
——爱因斯坦


--------------------------------------------------------------------------------
Java新手的通病[0]:概述
  其实很早以前就想写这样一个短文,可惜当时我没有Blog,所以到现在才写下来。
  最近几年,随着Java在Web应用和企业应用两个方面的普及,对Java程序员的需求量大增。因此Java程序员的数量也突然猛增(从TIOBE的排行榜可以看出来)。这虽然对Java社区来说是好事,但也暴露出一些问题。一方面由于大量的开发人员进入Java这个领域,相应的教学、培训跟不上;另一方面,很多进入Java领域的开发人员都比较浮躁,寄希望于"速成",没有耐心练好基本功。
  根据最近几年我面试Java程序员的经历以及对周围使用Java的同事的观察,我总结了一些共通的问题以及相应的解决方法。如果你是一个Java新手(刚学会Java不久,工作1-2年),你可以看看我说的通病是不是你也有,如果有的话,得赶紧补救一下了!
简单即是美!(Simple is beautiful)


--------------------------------------------------------------------------------

Java新手的通病[1]:对算法和数据结构不熟悉
  为什么我先拿"数据结构和算法"说事捏?这玩意是写程序最最基本的东东。不管你使用Java还是其它的什么语言,都离不开它。而且这玩意是跨语言的,学好之后不管在哪门语言中都能用得上。
  既然"数据结构和算法"这么重要,为什么很多Java新手却很不熟悉捏?我琢磨了一下,估计有两种可能。有些人虽然是计算机系毕业的,但是当初压根没好好学过这门课程,到工作时早都还给老师了;还有一些人是中途转行干编程,转行后又没有好好地打基础(都指望速成)。
  下面我列出几个很基本的问题,如果你每一个问题都搞得很清楚,那说明你过了这关,可以去看看下一个帖子了。否则的话,你赶紧去找本算法和数据结构的书恶补一下吧。

  什么时候该用数组型容器、什么时候该用链表型容器?
  什么是散列函数?HashMap的实现原理是什么?
  什么是递归?如果你以前从来没写过递归函数,尝试着写一个(比如用递归函数进行目录树遍历)。
  什么是算法复杂度?
  你是否理解空间换时间的思想?
  写一个针对整数数组的冒泡排序函数,看看你要修改几次才能跑通。
  写一个针对整数数组的二分查找函数,看看你要修改几次才能跑通。

设计软件有两种方法:一种是简单到极致而明显没有缺陷;另一种是复杂到极致以至于没有明显的缺陷。前者要难得多。
——C.A.R. Hoare

--------------------------------------------------------------------------------


Java新手的通病[2]:缺乏面向对象的基本功
  按理说Java是一个纯OO的语言,Java社区也一向是充满了"对象"的氛围。但我在面试Java程序员时,却屡屡碰到让我大跌眼镜的事情。我碰到不止一个求职者,连什么是"多态"都讲不清楚。很多人号称用过设计模式,但一半以上都仅限于单键模式和工厂模式。当我深入问他/她工厂模式到底有什么好处时,很多人语焉不详。
  为什么很多Java程序员会缺乏面向对象基本功?这得怪那些Java框架。现在Java的各种框架太发达、太傻瓜化了,导致很多程序员只需要按部就班、照着框架进行代码填空,基本已经丧失了OOA和OOD的能力。我手下有些个Java程序员,对Spring、Hibernate等框架了如指掌;但如果给他一个简单需求,让他写一个脱离Web框架的独立Application,他就不知所措了。这样的开发人员,将来只能成为所谓的"软件蓝领",岗位很难得到提升。
  同上一个帖子一样,我这次也提如下几个问题:
  基于接口的继承和基于实现的继承各有什么优点、缺点?
  继承(包括extend和implement)有什么缺点?
  多态有什么缺点?
  为什么Java可以多继承interface,而不可以多继承class?
  假如让你写一个小游戏(比如人机对战的五子棋),你会如何设计类结构?
  类结构设计时,如何考虑可扩展性?

  如果上述这些问题你都能够搞得比较清楚,说明你的OO基础还过得去。否则的话,我建议你一边找些OOAD和设计模式的书看看,同时自己动手写些简单的小程序(不依赖那些框架),把学到的模式理论结合到实践中。通过这种方式来提高自己OOAD的能力,效果会比较好。
软件就像性一样,免费的时候更好。
——Linus Torvalds(Linux之父)


--------------------------------------------------------------------------------

Java新手的通病[3]:缺少良好的编程习惯
  上次聊了“缺乏面向对象基本功”,今天来说说编程习惯的问题。今天说的这些坏习惯大部分都是跨语言的(C++、Python新手也有),而且大部分都需要靠平时不断地努力才能慢慢改掉。
  ●随意地命名
  有些新手写程序,当需要定义某个变量名(也可能是函数名、类名、包名等)时,随意地一敲键盘,名字就起好了......若干星期后,碰到某bug,再来看自己写的代码时,心中暗自嘀咕:“这代码是我写的吗?咋都看不懂捏?”
  所以我常跟新来的菜鸟说,命名不规范害死人啊!鉴于该问题相当普遍,我整理了几种典型的作为反面教材,具体如下:使用单字母命名变量;使用一些没太大意义的变量名(例如s1、s2、s3);对同一个业务概念使用不同的术语/缩写(容易让读代码的人神经分裂);使用用拼音命名(如果你团队中有港台人士或者老外,就惨了)。
  ●习惯于代码的copy & paste
  这是一个很普遍的问题。很多新手写代码的时候,如果发现要写的某个函数和前几天写的某个函数差不多,就把原来的那个函数贴过来,然后稍微改几下,心中还暗喜:“又快速搞定了一个功能”......
  同学,如果你也喜欢这么干,可要注意了。这种做法是代码臭味(借用《重构 - 改善既有代码的设计》的提法)的主要来源,导致代码可维护性大大下降。当你将来需要增加功能或修改bug的时候,要同时改动多个地方,而那时你估计已经想不起来这砣代码有几个克隆了。
  ●Magic Number满天飞
  先来看一个例子:假设有个业务逻辑中需要进行10秒的超时等待,你会怎么写这个sleep语句?我估计大部分人不外乎下面三种写法。
  1、直接写上sleep(10*1000);了事
  2、定义一个常量TIMEOUT_XXX = 10*1000;然后sleep(TIMEOUT_XXX);
  3、在配制文件中加入一个超时项,然后程序读取配制文件获得超时值,然后调用sleep。
  如果你的做法类似于写法1,你就属于有随手硬编码的习惯。硬编码不光缺乏可读性,而且具有和上述类似的代码臭味(可能会存在多个Magic Number克隆),不利于日后维护。
  至于写法2,比写法1稍好(至少可读性好了),但将来如果需要有变更,要调整超时时间(甚至要求由用户配制超时时间),则写法2的缺点立马暴露无遗。
  ●代码耦合度太大
  每当说到MVC或者设计模式,几乎每个Java开发人员都能说得头头是道?但是说归说,真正写代码的时候,鲜有人写出的代码是层次清楚的。至于说到代码耦合分别由哪些情况引起?什么是正交的设计?(关于耦合与正交设计,我后面会专门讨论一下)能完全搞明白的人就更少了。
  所以很多Java新手的代码耦合度大也就不足为奇了。我曾经抽查过试用期员工的代码,各种业务逻辑纠缠在一起,代码臭味都要熏死人。想重构都无从下手,只好让他推倒重写。
  ●被GC宠坏
  由于Java在语言层面提供了内存的垃圾回收机制,程序员只管申请内存,不需要再关心释放的问题。因此很多新手养成了坏习惯,对于其它资源(比如数据库连接)也只申请不释放(有些人甚至天真地以为JVM会帮你搞定资源回收)。
  还有些人虽然知道资源需要释放,但是常常忘记(比如写了打开数据库连接和相关代码,即将写关闭数据库连接时,突然有人叫你去吃中饭,回来后就把这茬给忘了)。
  这个坏习惯会导致资源的泄露,而资源泄露往往比内存泄露更要命。如果你写的程序是长时间运行的(比如运行在WebServer上),时间长了会由于资源耗尽而导致整个进程出问题。
杀死一个程序员不必用刀,只要改3次需求。


--------------------------------------------------------------------------------


Java新手的通病[4]:异常处理使用不当
  上一个帖子讨论了“编程习惯的问题”,今天来聊聊关于异常处理的话题。

  ●空catch语句块
  犯这种错误的人比较少,一般发生在刚学会Java或者刚参加工作不久的人身上。
  所谓“空catch语句块”就是在catch语句块中没有对异常作任何log处理,导致异常信息被丢弃掉。一旦程序不能正确运行,由于查不到任何log信息,只好从头看代码,靠肉眼找bug。

  ●没有使用finally
  很多人在catch语句之后不使用finally语句。由于在try语句中可能会涉及资源的申请和释放。如果在资源申请之后、资源释放之前抛出异常,就会发生资源泄露(资源泄露的严重性,上一个帖子已经聊过了)。

  ●笼统的catch语句块
  有些人为了省事,只在自己模块的最外层代码包一个try语句块,然后catch(Exception)。不管捕获到什么异常,都作统一log了事。这种做法比“空catch语句块”稍好,但由于不能对具体的异常进行具体处理,对一些可恢复的异常(下面会提到),丧失了恢复的机会。而且也可能导致上述提到的资源泄露的问题。

  ●使用函数返回值进行错误处理
  有些人放着Java的异常机制不用,而用函数返回值来表示成功/失败(比如返回true表示成功、返回false表示失败),简直是“捧着金碗要饭”。个人感觉,从C转到Java的人比较容易有此毛病。这种做法会导致如下几个问题:
  返回值一般用整数值或布尔值表示,传递的信息过于简陋;
  一旦调用者忽略了错误返回码,就会导致和“空catch语句块”类似的问题;
  对同一个函数的多处调用,都需要对返回值进行重复判断,导致代码冗余(代码冗余的坏处,上一个帖子也已经聊过了)。

  ●不清楚Checked Exception和Runtime Exception的区别
  这个现象比较普遍,我发现很多2年以上Java工作经验的人尚未完全搞明白两者的区别。看来这个问题得详细说一下。
  当初Java的设计者有意区分这两种异常,是别有深意的。其中“Checked Exception”用于表示可恢复的异常(也就是你必须检查的异常);而“Runtime Exception”表示不可恢复的异常(也就是运行时异常,主要是程序bug和致命错误,你不需要检查)。不过这种做法引来了很多争议(包括很多Java大牛),鉴于本帖子主要针对新手,以后再专门来聊这个争议的话题。
  为了便于理解,下面我举一个例子来说明。假设你要写一个Download函数,根据传入的URL(String参数)返回对应网页的内容文本。这时候有两种情况你需要处理:
  1、如果传入的URL参数是null,这表明该函数的调用者出bug了,而程序本身的bug是很难在运行时自我恢复的。这时候Download函数必须抛出Runtime Exception。并且Download函数的调用者不应该捕获这个异常,必须让它立即暴露出来(比如让JVM自己终止运行)。
  2、如果传入的URL参数非null,但是它包含的字符串不是一个合法的URL格式(可能由于用户输入错误导致)。这时候Download函数必须抛出Checked Exception。并且Download函数的调用者必须捕获该异常并进行相应的处理(比如提示用户重新输入URL)。
分享到:
评论

相关推荐

    编程随想博客文集 2010

    编程随想博客文集 2010

    编程随想博客文集 2009

    编程随想博客文集 2009

    编程随想博客匿名术文集 2009~2015

    编程随想博客匿名术文集 2009~2015

    opensource, 【编程随想】收藏的开源项目清单.zip

    opensource, 【编程随想】收藏的开源项目清单

    编程随想:Java新手的通病.docx

    在编程领域,尤其是对于Java新手来说,经常会遇到一些常见的问题和误区。本文将探讨Java新手在学习过程中普遍存在的通病,并提出相应的解决策略。 首先,我们来看第一个通病:对算法和数据结构的不熟悉。算法和数据...

    毕业设计-Jiajun的编程随想.zip

    这里为你收集整理了关于毕业设计、课程设计可参考借鉴的资料一份,质量非常高,如果你投入时间去研究几天相信肯定对你有很大的帮助。到时候你会回来感谢我的。 本资源是经过本地编译测试、可打开、可运行的项目、...

    博客:Jiajun的编程随想

    嘉俊的博客 会当凌绝顶,一览众山小。 欢迎订阅电报频道:分享初步相关的精选文章 目录 2021/01/27- 2021 13- 2021/01/03-如何 2021/01/03-Deeplink 路由 2021/ 02- 2020/12/ 2020/12/22- ...202

    代码随想录算法PDF.rar

    《代码随想录》是一本深受程序员喜爱的算法学习书籍,尤其对于初学者来说,它提供了深入浅出的讲解和实战演练。这本书的核心是通过实际编程来帮助读者理解和掌握算法,提升编程技能,特别是C++语言的应用。在C++这个...

    代码随想录算法PDF.zip

    通过学习《代码随想录》中的算法知识,不仅可以提升编程技能,还能帮助开发者在面试中脱颖而出,解决实际工作中遇到的复杂问题。无论你是初学者还是有经验的开发者,这本书都能提供宝贵的指导。阅读PDF版,你可以...

    代码随想录+刷题笔记记录

    代码随想录是一个致力于帮助程序员提高编程能力的网站,提供了大量的题目和解题思路供学习和参考。本文主要介绍代码随想录的刷题笔记记录,方便读者更好地利用该网站进行学习。 ## 刷题笔记记录的作用 刷题笔记...

    《代码随想录》最新PDF全集整理发布

    内容概要:这是关于作者针对自己的代码学习笔记《代码随想录》,进行两年后的全面更新与汇总的一则公告。新的PDF版本整合了所有最新内容,并修复和完善了一系列题目解释。尽管如此,作者仍推荐优先在网站上阅读以...

    软件随想录.pdf

    3. 编程范式:过程式编程、面向对象编程、函数式编程等。 4. 设计模式:常用的设计模式,如工厂模式、单例模式、策略模式等。 5. 软件架构:微服务架构、SOA(面向服务的架构)、MVC(模型-视图-控制器)架构等。 6....

    软件随想录全集

    4. **极限编程(XP)**:书中也提到了极限编程的一些实践,如结对编程、测试驱动开发(TDD)和持续集成。这些方法旨在减少错误,增强团队协作,提高软件质量。 5. **模式语言**:Martin Fowler是软件设计模式的积极推动...

    软件随想录 软件随想录

    软件的成功与否往往取决于团队协作、项目规划和沟通效率,而非单纯的编程技术。 2. **敏捷开发理念**:作者提倡敏捷开发方法,强调快速响应变化,通过迭代和增量的方式交付软件。敏捷方法的核心价值在于提高灵活性...

    代码随想录的pdf版本,需要准备秋招的小伙伴们看过来呀!

    《代码随想录》是一本深受程序员喜爱的书籍,尤其对于即将参加秋季招聘的计算机科学和技术专业的学生们来说,它是提升编程技能和算法能力的重要资源。这本书深入浅出地讲解了编程思维和各种常见算法,旨在帮助读者...

    代码随想录 动态规划、回溯、递归、二叉树、贪心

    《代码随想录》是一本深受程序员喜爱的编程学习资料,尤其在算法领域,它提供了丰富的实例和深入的解析,帮助读者理解并掌握动态规划、回溯、递归、二叉树以及贪心等核心算法。这些算法是解决复杂计算问题的基础工具...

    随想命令按钮控件 V3.0 Build 0401.zip

    随想命令按钮控件的源码包含C++或VB等编程语言编写的代码,通过分析和学习这些代码,开发者可以掌握如何实现高级控件功能,提升自己的编程技能。 资源文件通常包含用于控件展示的图像、图标和其他多媒体素材,这些...

    《代码随想录》双指针算法及其应用详解

    本文围绕程序员Carl撰写的《代码随想录》,全面系统地阐述了一系列重要的利用双指针算法解决编程问题的方法,并深入解析了其背后的逻辑与实现细节。涵盖典型题目包括:27号题目移除元素,力扣上排名第15和第18的三数...

    代码质量随想录

    在编程世界里,代码质量的重要性不言而喻。"代码质量随想录"是一系列文档,旨在引导初学者和有经验的开发者优化他们的编码习惯,从而提升代码质量,成为更出色的程序员。以下是对这些文件主题的详细解读: 1. **...

Global site tag (gtag.js) - Google Analytics