Refactoring Patterns (First Part)

refactoring Patterns:第一部分
内容:
介绍
什么是Refactoring?
Refactoring原则
参考资料
关于作者
相关内容:
该系列的其他部分

石一楹 (shiyiying@hotmail.com)
浙江大学灵峰科技开发公司技术总监
2001 年 12 月

这是关于refactoring思考的第一部分内容。本文将介绍refactoring的基本概念、定义,同时解释正确、安全进行refactoring需要坚持的几个原则。

介绍
代码太容易变坏。代码总是趋向于有更大的类、更长的方法、更多的开关语句和更深的条件嵌套。重复代码随处可见,特别是那些初看相似细看又不同的代码泛滥于整个系统:条件表达式,循环结构、集合枚举….信息被共享于系统一些关系甚少的组成部分之间,通常,这使得系统中几乎所有的重要信息都变成全局或者重复。你根本不能看到这种代码还有什么良好的设计。(如果有的话,也已经不可辨识了。)

这样的代码难以理解,更不要说对它加以修改。如果你关心系统体系结构、设计,或者是一个好程序,你的第一反应就是拒绝工作于这样的代码。你会说:"这么烂的代码,让我修改,还不如重写。"然而,你不大可能完全重写已经能够甚至是正在运作的系统,你不能保证新的系统能够实现全部的原有功能。更何况,你不是生活在真空,还有更多的投资、交付、竞争压力。

于是你使用一种quick-and-dirty的方法,如果系统有问题,那么就直接找到这个问题,便当地修改它。如果要增加一个新功能,你会从原来的系统中找到一块相近的代码,拷出来,作些修改。对于原来的系统,你想,既然我不能重头写过,而且它们已经在运作,让它去吧。然后,你增加的代码变成了下一个程序员咒骂的对象。系统越来越难以理解,维护越来越困难、越来越昂贵。系统变成了一个十足的大泥球。

这种情况是每一个人都不愿意碰到的,但是奇怪的是,这样的情景一次又一次出现在大多数人的编程生涯中。这是因为我们不知道该如何解决。

解决这个问题的最好办法当然是让它不要发生。然而,要阻止代码的腐化,你需要付出额外的代价。每次在修改或增加代码之前,你都要看一看手上的这些代码。如果它有很好的味道,那么你应该能够很方便地加入新的功能。如果你需要花很长的时间去理解原来的代码,花更长的时间去增加和修改代码。那么,先放下手里的活,让我们来做Refactoring。

什么是Refactoring?
每个人似乎都有自己的Refactoring的定义,尽管他们讲的就是同一件事情。在那么多的定义中,最先对Refactoring进行理论研究的Raloh Johnson的话显然更有说服力:
Refactoring是使用各种手段重新整理一个对象设计的过程,目的是为了让设计更加灵活并且/或者更可重用。你可能有几个理由来做这件事情,其中效率和可维护性可能是最重要的原因。

Martin Fowler[Fowler]把Refactoring定义为两部分,一部分为名词形式:
Refactoring(名词):在不改变可观察行为的前提下,对软件内部结构的改变,目的是使它更易于理解并且能够更廉价地进行改变。

另一部分则是动词形式:
Refactor(动词):通过应用一系列不改变软件可观察行为的refactoring来重构一个软件。
Martin Fowler的名词形式就是说Refactoring是对软件内部结构的改变,这种改变的前提是不能改变程序的可观察的行为,这种改变的目的就是为了让它更容易理解,更容易被修改。动词形式则突出Refactor是一种软件重构行为,这种重构的方法就是应用一系列的refactoring。

软件结构可以因为各种各样的原因而被改变,如进行打印美化、性能优化等等,但只有出于可理解性、可修改、可维护目的的改变才是Refactoring。这种改变必须保持可观察的行为,按照Martin的话来说,就是Refactoring之前软件实现什么功能,之后照样实现什么功能。任何用户,不管是终端用户还是其他的程序员,都不需要知道某些东西发生了变化。

Refactoring原则

Two Hats(两顶帽子)
Kent Beck提出这个比方。他说,如果你在使用Refactoring开发软件,你把开发时间分给两个不同的活动:增加功能和refactoring。增加功能时,你不应该改变任何已经存在的代码,你只是在增加新功能。这个时候,你增加新的测试,然后让这些新测试能够通过。当你换一顶帽子refactoring时,你要记住你不应该增加任何新功能,你只是在重构代码。你不会增加新的测试(除非发现以前漏掉了一个)。只有当你的Refactoring改变了一个原先代码的接口时才改变某些测试。

在一个软件的开发过程中,你可能频繁地交换这两顶帽子。你开始增加一个新功能,这时你认识到,如果原来的代码结构更好一点,新功能就能够更方便地加入。因此,你脱下增加功能的帽子,换上refactoring的帽子。一会儿,代码结构变好了,你脱下refactoring的帽子,戴上增加功能的帽子。增加了新功能以后,你可能发现你的代码使得程序的结构难以理解,这时你又交换帽子。

关于两顶帽子交换的故事不断地发生在你的日常开发中,但是不管你带着哪一定帽子,一定要记住带一定帽子只做一件事情。

Unit Test
保持代码的可观察行为不变称为Refactoring的安全性。Refactoring工具用半形式化的理论证明来保证Refactoring的安全性。

但是,要从理论上完全证明系统的可观察行为保持不变,虽然不是说不可能,也是十分困难的。工具也有自己的缺陷。首先,目前对于Refactoring的理论研究并非十分成熟,某些曾经被证明安全的Refactoring最近被发现在特定的场合下并不安全。其次,目前的工具不能很好地支持"非正式"的Refactoring操作,如果你发现一种新的Refactoring技巧,工具不能立即让这种refactoring为你所用。

自动化的测试是检验Refactoring安全性非常方便而且有效的方法。虽然我们不能穷尽整个系统中所有的测试,但如果在Refactoring之前成功的测试现在失败了,我们就会知道刚刚做的Refactoring破坏了系统的可观察行为。自动化测试能够在程序员不进行人工干预的情况下自动检测到这样的行为破坏。

自动化测试中最实用的工具是XUnit系列单元测试框架,该框架最初由Kent Beck和Eric Gamma为Smalltalk社团而开发。

Eric Gamma对测试的重要性曾经有过这样的话:
你写的测试越少,你的生产力就越低,同时你的代码就变得越不稳定。你越是没有生产力、越缺少准确性,你承受的压力就越大......

下面的片断来自Javaworld,两个Sun开发者展示了它们对单元测试的狂热以及展示了它们扩展单元测试来检查象EJB这样的分布式控件:
我们从来没有过度测试软件,相反我们很少做得足够。。。但愿测试是软件开发过程中关键但却经常被误解的一部分。对每一个代码单元而言,单元测试确保他自己能够工作,独立于其他单元。在面向对象语言中,一个单元通常,但并不总是,一个类的等价物。如果一个开发者确信应用程序的每一个片断能够按照它们被设计的方式正确工作,那么他们会认识到组装得到的应用程序发生的问题必定来自于把所有部件组合起来的过程中。单元测试告诉程序员一个应用程序' pieces are working as designed'。

我曾经认为自己是很好的程序员。认为自己的代码几乎不可能出错。但事实上,我没有任何证据可以证明这一点,同样我也没有信心我的代码就一定不会出错,或者当我增加一项新功能时,原先的行为一定没有遭到破坏。另一方面,我认为太多的测试于事无补,测试只能停留在理论之上,或只有那些实力强劲的大公司才能做到。

这个观点在1999年我看到Kent Beck和Gamma的Junit测试框架之后被完全推翻了。JUnit是XP的重要工具之一。XP提倡一个规则叫做test-first design。采用Test First Design方法,你在编写一个新功能前先写一个单元测试,用它来测试实现新功能需要但可能会出错的代码。这意味着,测试首先是失败的,写代码的目的就是为了让这些测试能够成功运行。

JUnit的简单、易用和强大的功能几乎让我立刻接纳了单元测试的思想,不但因为它可以让我有证据表明我的代码是正确的,更重要的是在我每次对代码进行修改的同时,我有信心所有的变化都不会影响原有的功能。测试已经成为我所有代码的一部分。关于这一点,Kent Beck在它的《Extreme Programming Explained》中指出:
简直不存在一个不带自动化测试的程序。程序员编写单元测试,因而他们能够确信程序操作的正确性成为程序本身的一部分。同时,客户编写功能测试,因而他们能够确信程序操作的正确性成为程序本身的一部分。结果就是,随着时间的推移,一个程序变得越来越可信-他变得更加能够接受改变,而不是相反。

单元测试的基本过程如下:

  1. 设计一个应当失败的测试
  2. 编译器应当立刻反映出失败。因为测试中需要使用的类和方法还没有实现。
  3. 如果有编译错误,完成代码,只要让编译通过即可,这时的代码只反映了代码的意图而并非实现。
  4. 在JUnit中运行所有的测试,它应当指示测试失败
  5. 编写实际代码,目的是为了让测试能够成功。
  6. 在Junit中运行所有的测试,保证所有的测试全部通过,一旦所有的测试通过,停止编码。
  7. 考虑一下是否有其他情况没有考虑到,编写测试,运行它,必要时修改代码,直至测试通过


在编写测试的时候,要注意对测试的内容加以考虑,并不是测试越多越好.Kent Beck说:
你不必为每一个方法编写一个测试,只有那些可能出错的具有生产力的方法才需要。有时你仅仅想找出某些事情是可能的。你探索一半个小时。是的,它有可能发生。现在你抛弃你的代码并且从单元测试重新开始。

另一位作者Eric Gamma说:
你总是能够写更多的测试。但是,你很快就会发现,你能够想象到的测试中只有一部分才是真正有用的。你所需要的是为那些即使你认为它们应当工作还会出错的地方编写测试,或者是你认为可能会失败但最终还是成功的地方。另一种方法是以成本/收益的角度来考虑。你应该编写反馈信息物有所值的测试。

你可能会认为单元测试虽然好,但是它会增加你的编程负担,而别人花钱是请你来写代码,而不是来写测试的。但是WILLAM WAKE说:
编写单元测试可能是一件乏味的事情,但是它们为你节省将来的时间(通过捕获改变后的bug).相对不明显,但同样重要的是,他们能够节约你现在的时间:测试聚焦于设计和实现的简单性,它们支持refactoring,它们在你开发一项特性的同时对它进行验证。

你还会认为单元测试可能增加你的维护量,因为如果代码发生了改变,相应的测试也需要做出改变。事实上,测试只会让你的维护更快,因为它们让你对你所做出的改变更有信心,如果你做错了一件事,测试同时也会提醒你。如果接口发生了改变,你当然需要改变你的接口,但这一点并非太难。

单元测试是程序的一部分,而不是独立的测试部门所应完成的任务。这就是所谓的自测试代码。程序员可能花费一些时间在编写代码,花费一些时间在理解别人的代码,花费一些时间在做设计,但他们最多的时间是在做调试。任何一个人都有这样一种遭遇,一个小小的问题可能花费你一个下午、一天,甚至是几天的时间来调试。要改正一个bug往往很简单,但是要找到这样的bug却是一个大问题。如果你的代码能够带有自动化的自测试,那么一旦你加入一个新的功能,旧的测试会告诉你那些原来的代码存在着bug,而新加入的测试则告诉哪些新加入的代码引入了bug。

Small step
Refactoring的另一个原则就是每一步总是做很少的工作,每做少量修改,就进行测试,保证refactoring的程序是安全的。

如果你一次做了太多的修改,那么就有可能介入很多的bug,代码将难以调试。如果你发现修改并不正确,要想返回到原来的状态也十分困难。

这些细小的步骤包括:

  1. 寻找需要refactoring的地方。这些地方可能在理解代码、扩展系统的时候被发现。或者是通过闻代码的味道而找到。或者通过某些代码分析工具。
  2. 如果对需要Refactoring的代码还没有单元测试,首先编写单元测试。如果已经有了单元测试,看一看该单元测试是否考虑到了你所面对的问题,不然就完善它。
  3. 运行单元测试,保证原先的代码是正确的。
  4. 根据代码所呈现的现象在头脑中反映该做什么样的refactoring,或者找一本关于Refactoring分类目录的书放在面前,查找相似的情况,然后按照书中的指示一步一步进行Refactoring。
  5. 每一步完成时,都进行单元测试,保证它的安全性,也就是可观察行为没有发生改变。
  6. 如果Refactoring改变了接口,你需要修改测试套件
  7. 全部做完后,进行全部的单元测试,功能测试,保证整个系统的可观察行为不受影响。如果你按照这样的步骤去做Refactoring,那么可能出错的机会就很小,正如Kent Beck所说:"I'm not a great programmer; I'm just a good programmer with great habits".


要求使用小步骤渐进地Refactoring并不完全出于对实践易行的考虑。

Ralph Johnson在伊利诺斯州立大学领导的一个研究小组是Refactoring理论的引导者和最重要的理论研究团体。其中William Opdyke 1992年的博士论文《Refactoring Object-Oriented Framework》是公认的Refactoring第一位正式提出者。在那篇论文中,Opdyk描述他对refactoring重构层次的看法:
通常,人们要么在按照增加到系统的特性这样一个高层次上,要么按照被改变的代码行这样一种低层次来看待软件的变化。Refactorings是一种重组织计划,它支持在一个中间层次上的改变。例如,考虑一下,refactoring把一个类的成员函数移到另外一个类。。。。

为了实现这样的intermediate level操作,Opdyke提出了原子atomic refactoring的概念,他指出:
下面列出的支持refactoring最终的分类是原子的;也就是说,它们是最原始级别的refactorings。原子refactoring创建、删除、改变及移动实体…
… 高层refactoring通过这26个低层(原子)refactoring得到支持

论文中,Opdyke 首先证明在一定的前提之下,这些原子refactoring将不会改变程序的Observable behaviour。更高层的refactoring可以通过分解为这些原子的refactoring加以证明。Opdyke也证明了他所提出的高层refactoring如何在每一步原子atomic之后都符合后续原子atomic所需要的前提。

小步前进使得对每一步进行证明成为可能,最终通过组合这些证明,可以从更高层次上来证明这些refactoring的安全性和正确性。

Refactoring工具依赖于这些理论研究进行Refactoring。如果每个人能够按照这样的一小步一小步进行Refactoring,那么极有希望他的refactoring能够被正确地记录下来,为整个面向对象社团所用。同时,对他理论正确性地证明可以促使refactoring工具得到进一步的发展。

也许你会认为,随着工具的发展,程序员将变成Refactoring机器人。这样的看法是不正确的。

虽然使用一个refactoring工具能够避免介入使用手工方式可能产生的各种各样bug,减少编译、测试和code review。但是正如Smalltalk Refactory Browser的作者Don Roberts所说,Refactoring工具不打算用来代替程序员,程序员需要自己来决定什么地方需要refactoring,做什么样的refactoring。而在这一点上,经验是不可代替的。

Code Review和Pair Programming
要保证refactoring的正确性,还有一种很有用的方法就是进行Code Review。

Code Review原先一般都在一些大公司实行,他们可能聘请专家对项目进行Code Review,以发现代码中存在的问题,改良系统的设计,提高程序员的水平。

同样在refactoring过程中,我们也可以使用Code Review的方法。问题是,我们是否有足够的精力和人员配备来进行这样的Review呢?

XP成功经验表明,Code Review不应当是只有大公司才能做的。甚之,XP中的Pair Programming其实就是对Code Review的极端化,它也更加适合于表达Code review在refactoring过程中所能起到的作用。Kent Beck说:

在每一对中有两个角色。一个合作者,把持键盘和鼠标,正在考虑该处所实现方法的最佳途径,。另一个合作者,则更多考虑策略性方面的问题:

  1. 这是完成工作的所有过程吗?
  2. 还有没有其他的测试套件还不能工作?
  3. 还有没有其他的方法可以简化整个系统,从而使得当前的问题不再出现?


使用这种方法进行refactoring,可以在一个程序员没有想到一个应当有的单元测试时,当一个程序员无法找到合适的Refactoring方法或者当一个程序员没有按照正确的方法进行refactoring时,另外一个程序员可以提出自己的观点和建议。甚至在极端情况下,当拥有键盘的程序员对如何完成这个refactoring没有概念时,另外一个程序员可以接过键盘,直接往下做。

XPChina的notyy认为Code Review不应当属于refactoring的原则之一。严格来你可以在不实行Pair Programming或者Code Review的情况下进行refactoring.但是由于refactoring的特殊性,它不是增加新的代码,而是修改已经存在、很可能已经被其他许多模块依赖的代码,所以Pair Programming在这里比一般的新代码更重要。从另一个方面来讲,如果你正在做big refactory,如refactor to Design pattern,此时Pair Programming更有助于交流双方对于被修整代码将refactor成为何种设计模式的意见。

因此,尽管这不是一条必要的原则,我还是把它作为原则之一进行描述。

The Rule of Three
Don Roberts提出的The Rule of Three好像和Pattern社团对模式的验证十分相似:

第一次做某件事,你直接做就是了。第二次你做某件事,看到重复,你有些退缩,但不管怎样,你重复就是了。第三次你做类似的事情,你refactor。

关于作者
石一楹,现任浙江大学灵峰科技开发公司技术总监。多年从事OO系统分析、设计。现主要研究方向为Refactoring和分析模式。你可以通过
shiyiying@hotmail.com和我联系。
Language support for Java ™ for Visual Studio Code Visual Studio Marketplace Installs Join the chat at https://gitter.im/redhat-developer/vscode-java Build Status License Provides Java ™ language support via Eclipse ™ JDT Language Server, which utilizes Eclipse ™ JDT, M2Eclipse and Buildship. Quick Start Install the Extension On the following platforms, the extension should activate without any setup : win32-x64, darwin-x64, darwin-arm64, linux-x64, linux-arm64. If on another platform, or using the "universal" version, you can set a Java Development Kit. It must be Java 21 or above. Optionally, download and install a Java Development Kit for your project (Java 1.8 or above is supported). See Project JDKs for more details Extension is activated when you first access a Java file Recognizes projects with Maven or Gradle build files in the directory hierarchy. Features screencast Supports code from Java 1.8 to Java 24 Maven pom.xml project support Gradle project support (with experimental Android project import support) Standalone Java files support As-you-type reporting of parsing and compilation errors Code completion Code/Source actions / Refactoring Javadoc hovers Organize imports triggered manually or on save when pasting code into a java file with Ctrl+Shift+v (Cmd+Shift+v on Mac). Type search Code outline Code folding Code navigation Code lens (references/implementations) Highlights Code formatting (on-type/selection/file) Code snippets Annotation processing support (automatic for Maven projects) Semantic selection Diagnostic tags Call Hierarchy Type Hierarchy To launch and debug your Java programs, it's recommended you install Java Debug Extension for Visual Studio Code. See the changelog for the latest release. You might also find useful information in the project Wiki. Setting the JDK Java Tooling JDK Now that Java extension will publish platform specific versions, it will embed a JRE for supported platforms such as win32-x64, linux-x64, linux-arm64, darwin-x64, darwin-arm64. The embedded JRE is used to launch the Language Server for Java. Users are only responsible for configuring Project JDKs to compile your Java projects. The following part is only kept for the universal version without embedded JRE. The tooling JDK will be used to launch the Language Server for Java. And by default, will also be used to compile your projects. Java 21 is the minimum required version. The path to the Java Development Kit can be specified by the java.jdt.ls.java.home setting in VS Code settings (workspace/user settings). If not specified, it is searched in the following order until a JDK meets current minimum requirement. the JDK_HOME environment variable the JAVA_HOME environment variable on the current system path Project JDKs If you need to compile your projects against a different JDK version, it's recommended you configure the java.configuration.runtimes property in your user settings, eg: "java.configuration.runtimes": [ { "name": "JavaSE-1.8", "path": "/path/to/jdk-8", }, { "name": "JavaSE-11", "path": "/path/to/jdk-11", }, { "name": "JavaSE-24", "path": "/path/to/jdk-24", "default": true }, ] The default runtime will be used when you open standalone Java files. Available commands The following commands are available: Switch to Standard Mode: switches the Java Language Server to Standard mode. This command is only available when the Java Language Server is in LightWeight mode. Java: Reload Projects (Shift+Alt+U): It forces project configuration / classpath updates (eg. dependency changes or Java compilation level), according to the project build descriptor. Java: Import Java Projects into Workspace: detects and imports all the Java projects into the Java Language Server workspace. Java: Open Java Language Server Log File: opens the Java Language Server log file, useful for troubleshooting problems. Java: Open Java Extension Log File: opens the Java extension log file, useful for troubleshooting problems. Java: Open All Log Files: opens both the Java Language Server log file and the Java extension log file. Java: Force Java Compilation (Shift+Alt+B): manually triggers compilation of the workspace. Java: Rebuild Projects: manually triggers a full build of the selected projects. Java: Open Java Formatter Settings: opens the Eclipse formatter settings. Creates a new settings file if none exists. Java: Clean Java Language Server Workspace: cleans the Java language server workspace. Java: Attach Source: attaches a jar/zip source to the currently opened binary class file. This command is only available in the editor context menu. Java: Add Folder to Java Source Path: adds the selected folder to its project source path. This command is only available in the file explorer context menu and only works for unmanaged folders. Java: Remove Folder from Java Source Path: removes the selected folder from its project source path. This command is only available in the file explorer context menu and only works for unmanaged folders. Java: List All Java Source Paths: lists all the Java source paths recognized by the Java Language Server workspace. Java: Show Build Job Status: shows the Java Language Server job status in Visual Studio Code terminal. Java: Go to Super Implementation: goes to the super implementation for the current selected symbol in editor. Java: Restart Java Language Server: restarts the Java language server. Supported VS Code settings The following settings are supported: java.home : Deprecated, please use 'java.jdt.ls.java.home' instead. Absolute path to JDK home folder used to launch the Java Language Server. Requires VS Code restart. java.jdt.ls.lombokSupport.enabled: Whether to enable lombok support. Defaults to true. java.jdt.ls.vmargs : Extra VM arguments used to launch the Java Language Server. Requires VS Code restart. java.errors.incompleteClasspath.severity : Specifies the severity of the message when the classpath is incomplete for a Java file. Supported values are ignore, info, warning, error. java.trace.server : Traces the communication between VS Code and the Java language server. java.configuration.updateBuildConfiguration : Specifies how modifications on build files update the Java classpath/configuration. Supported values are disabled (nothing happens), interactive (asks about updating on every modification), automatic (updating is automatically triggered). java.configuration.maven.userSettings : Path to Maven's user settings.xml. java.configuration.checkProjectSettingsExclusions: Deprecated, please use 'java.import.generatesMetadataFilesAtProjectRoot' to control whether to generate the project metadata files at the project root. And use 'files.exclude' to control whether to hide the project metadata files from the file explorer. Controls whether to exclude extension-generated project settings files (.project, .classpath, .factorypath, .settings/) from the file explorer. Defaults to false. java.referencesCodeLens.enabled : Enable/disable the references code lenses. java.implementationCodeLens : Enable/disable the implementations code lens for the provided categories. java.signatureHelp.enabled : Enable/disable signature help support (triggered on (). java.signatureHelp.description.enabled : Enable/disable to show the description in signature help. Defaults to false. java.contentProvider.preferred : Preferred content provider (see 3rd party decompilers available in vscode-java-decompiler). java.import.exclusions : Exclude folders from import via glob patterns. Use ! to negate patterns to allow subfolders imports. You have to include a parent directory. The order is important. java.import.gradle.enabled : Enable/disable the Gradle importer. Specify the Gradle distribution used by the Java extension: java.import.gradle.wrapper.enabled: Use Gradle from the 'gradle-wrapper.properties' file. Defaults to true. java.import.gradle.version: Use Gradle from the specific version if the Gradle wrapper is missing or disabled. java.import.gradle.home: Use Gradle from the specified local installation directory or GRADLE_HOME if the Gradle wrapper is missing or disabled and no 'java.import.gradle.version' is specified. java.import.gradle.arguments: Arguments to pass to Gradle. java.import.gradle.jvmArguments: JVM arguments to pass to Gradle. java.import.gradle.user.home: setting for GRADLE_USER_HOME. java.import.gradle.offline.enabled: Enable/disable the Gradle offline mode. Defaults to false. java.import.maven.enabled : Enable/disable the Maven importer. java.autobuild.enabled : Enable/disable the 'auto build'. java.maxConcurrentBuilds: Set max simultaneous project builds. java.completion.enabled : Enable/disable code completion support. java.completion.guessMethodArguments : Specify how the arguments will be filled during completion. Defaults to auto. auto: Use off only when using Visual Studio Code - Insiders, other platform will defaults to insertBestGuessedArguments. off: Method arguments will not be inserted during completion. insertParameterNames: The parameter names will be inserted during completion. insertBestGuessedArguments: The best guessed arguments will be inserted during completion according to the code context. java.completion.filteredTypes: Defines the type filters. All types whose fully qualified name matches the selected filter strings will be ignored in content assist or quick fix proposals and when organizing imports. For example 'java.awt.*' will hide all types from the awt packages. java.completion.favoriteStaticMembers : Defines a list of static members or types with static members. java.completion.importOrder : Defines the sorting order of import statements. java.format.enabled : Enable/disable the default Java formatter. java.format.settings.url : Specifies the url or file path to the Eclipse formatter xml settings. java.format.settings.profile : Optional formatter profile name from the Eclipse formatter settings. java.format.comments.enabled : Includes the comments during code formatting. java.format.onType.enabled : Enable/disable on-type formatting (triggered on ;, } or <return>). java.foldingRange.enabled: Enable/disable smart folding range support. If disabled, it will use the default indentation-based folding range provided by VS Code. java.maven.downloadSources: Enable/disable download of Maven source artifacts as part of importing Maven projects. java.maven.updateSnapshots: Force update of Snapshots/Releases. Defaults to false. java.codeGeneration.hashCodeEquals.useInstanceof: Use 'instanceof' to compare types when generating the hashCode and equals methods. Defaults to false. java.codeGeneration.hashCodeEquals.useJava7Objects: Use Objects.hash and Objects.equals when generating the hashCode and equals methods. This setting only applies to Java 7 and higher. Defaults to false. java.codeGeneration.useBlocks: Use blocks in 'if' statements when generating the methods. Defaults to false. java.codeGeneration.generateComments: Generate method comments when generating the methods. Defaults to false. java.codeGeneration.toString.template: The template for generating the toString method. Defaults to ${object.className} [${member.name()}=${member.value}, ${otherMembers}]. java.codeGeneration.toString.codeStyle: The code style for generating the toString method. Defaults to STRING_CONCATENATION. java.codeGeneration.toString.skipNullValues: Skip null values when generating the toString method. Defaults to false. java.codeGeneration.toString.listArrayContents: List contents of arrays instead of using native toString(). Defaults to true. java.codeGeneration.toString.limitElements: Limit number of items in arrays/collections/maps to list, if 0 then list all. Defaults to 0. java.selectionRange.enabled: Enable/disable Smart Selection support for Java. Disabling this option will not affect the VS Code built-in word-based and bracket-based smart selection. java.showBuildStatusOnStart.enabled: Automatically show build status on startup, defaults to notification. notification: Show the build status via progress notification. terminal: Show the build status via terminal. off: Do not show any build status. For backward compatibility, this setting also accepts boolean value, where true has the same meaning as notification and false has the same meaning as off. java.project.outputPath: A relative path to the workspace where stores the compiled output. Only effective in the WORKSPACE scope. The setting will NOT affect Maven or Gradle project. java.project.referencedLibraries: Configure glob patterns for referencing local libraries to a Java project. java.completion.maxResults: Maximum number of completion results (not including snippets). 0 (the default value) disables the limit, all results are returned. In case of performance problems, consider setting a sensible limit. java.configuration.runtimes: Map Java Execution Environments to local JDKs. java.server.launchMode: Standard: Provides full features such as intellisense, refactoring, building, Maven/Gradle support etc. LightWeight: Starts a syntax server with lower start-up cost. Only provides syntax features such as outline, navigation, javadoc, syntax errors. The lightweight mode won't load thirdparty extensions, such as java test runner, java debugger, etc. Hybrid: Provides full features with better responsiveness. It starts a standard language server and a secondary syntax server. The syntax server provides syntax features until the standard server is ready. And the syntax server will be shutdown automatically after the standard server is fully ready. Default launch mode is Hybrid. Legacy mode is Standard java.sources.organizeImports.starThreshold: Specifies the number of imports added before a star-import declaration is used, default is 99. java.sources.organizeImports.staticStarThreshold: Specifies the number of static imports added before a star-import declaration is used, default is 99. java.imports.gradle.wrapper.checksums: Defines allowed/disallowed SHA-256 checksums of Gradle Wrappers. java.project.importOnFirstTimeStartup: Specifies whether to import the Java projects, when opening the folder in Hybrid mode for the first time. Supported values are disabled (never imports), interactive (asks to import or not), automatic (always imports). Default to automatic. java.project.importHint: Enable/disable the server-mode switch information, when Java projects import is skipped on startup. Defaults to true. java.import.gradle.java.home: Specifies the location to the JVM used to run the Gradle daemon. java.project.resourceFilters: Excludes files and folders from being refreshed by the Java Language Server, which can improve the overall performance. For example, ["node_modules",".git"] will exclude all files and folders named 'node_modules' or '.git'. Pattern expressions must be compatible with java.util.regex.Pattern. Defaults to ["node_modules",".git"]. java.templates.fileHeader: Specifies the file header comment for new Java file. Supports configuring multi-line comments with an array of strings, and using ${variable} to reference the predefined variables. java.templates.typeComment: Specifies the type comment for new Java type. Supports configuring multi-line comments with an array of strings, and using ${variable} to reference the predefined variables. java.references.includeAccessors: Include getter, setter and builder/constructor when finding references. Default to true. java.configuration.maven.globalSettings : Path to Maven's global settings.xml. java.configuration.maven.lifecycleMappings : Path to Maven's lifecycle mappings xml. java.eclipse.downloadSources : Enable/disable download of Maven source artifacts for Eclipse projects. java.references.includeDecompiledSources : Include the decompiled sources when finding references. Default to true. java.project.sourcePaths: Relative paths to the workspace where stores the source files. Only effective in the WORKSPACE scope. The setting will NOT affect Maven or Gradle project. java.typeHierarchy.lazyLoad: Enable/disable lazy loading the content in type hierarchy. Lazy loading could save a lot of loading time but every type should be expanded manually to load its content. java.codeGeneration.insertionLocation: Specifies the insertion location of the code generated by source actions. Defaults to afterCursor. afterCursor: Insert the generated code after the member where the cursor is located. beforeCursor: Insert the generated code before the member where the cursor is located. lastMember: Insert the generated code as the last member of the target type. java.codeGeneration.addFinalForNewDeclaration: Whether to generate the 'final' modifer for code actions that create new declarations. Defaults to none. none: Do not generate final modifier fields: Generate 'final' modifier only for new field declarations variables: Generate 'final' modifier only for new variable declarations all: Generate 'final' modifier for all new declarations java.settings.url : Specifies the url or file path to the workspace Java settings. See Setting Global Preferences java.symbols.includeSourceMethodDeclarations : Include method declarations from source files in symbol search. Defaults to false. java.quickfix.showAt : Show quickfixes at the problem or line level. java.configuration.workspaceCacheLimit : The number of days (if enabled) to keep unused workspace cache data. Beyond this limit, cached workspace data may be removed. java.import.generatesMetadataFilesAtProjectRoot : Specify whether the project metadata files(.project, .classpath, .factorypath, .settings/) will be generated at the project root. Defaults to false. java.inlayHints.parameterNames.enabled: Enable/disable inlay hints for parameter names. Supported values are: none(disable parameter name hints), literals(Enable parameter name hints only for literal arguments) and all(Enable parameter name hints for literal and non-literal arguments). Defaults to literals. java.compile.nullAnalysis.nonnull: Specify the Nonnull annotation types to be used for null analysis. If more than one annotation is specified, then the topmost annotation will be used first if it exists in your project dependencies. This setting will be ignored if java.compile.nullAnalysis.mode is set to disabled. java.compile.nullAnalysis.nullable: Specify the Nullable annotation types to be used for null analysis. If more than one annotation is specified, then the topmost annotation will be used first if it exists in your project dependencies. This setting will be ignored if java.compile.nullAnalysis.mode is set to disabled. java.compile.nullAnalysis.nonnullbydefault: Specify the NonNullByDefault annotation types to be used for null analysis. If more than one annotation is specified, then the topmost annotation will be used first if it exists in your project dependencies. This setting will be ignored if java.compile.nullAnalysis.mode is set to disabled. java.import.maven.offline.enabled: Enable/disable the Maven offline mode. Defaults to false. java.codeAction.sortMembers.avoidVolatileChanges: Reordering of fields, enum constants, and initializers can result in semantic and runtime changes due to different initialization and persistence order. This setting prevents this from occurring. Defaults to true. java.jdt.ls.protobufSupport.enabled: Specify whether to automatically add Protobuf output source directories to the classpath. Note: Only works for Gradle com.google.protobuf plugin 0.8.4 or higher. Defaults to true. java.jdt.ls.androidSupport.enabled: [Experimental] Specify whether to enable Android project importing. When set to auto, the Android support will be enabled in Visual Studio Code - Insiders. Note: Only works for Android Gradle Plugin 3.2.0 or higher. Defaults to auto. java.completion.postfix.enabled: Enable/disable postfix completion support. Defaults to true. java.completion.chain.enabled: Enable/disable chain completion support. Defaults to false. java.completion.matchCase: Specify whether to match case for code completion. Defaults to firstLetter. java.compile.nullAnalysis.mode: Specify how to enable the annotation-based null analysis. Supported values are disabled (disable the null analysis), interactive (asks when null annotation types are detected), automatic (automatically enable null analysis when null annotation types are detected). Defaults to interactive. java.cleanup.actionsOnSave: Deprecated, please use 'java.cleanup.actions' instead. The list of clean ups to be run on the current document when it's saved. Clean ups can automatically fix code style or programming mistakes. Click here to learn more about what each clean up does. java.cleanup.actions: The list of clean ups to be run on the current document when it's saved or when the cleanup command is issued. Clean ups can automatically fix code style or programming mistakes. Click here to learn more about what each clean up does. java.saveActions.cleanup: Enable/disable cleanup actions on save. java.import.gradle.annotationProcessing.enabled: Enable/disable the annotation processing on Gradle projects and delegate to JDT APT. Only works for Gradle 5.2 or higher. java.sharedIndexes.enabled: [Experimental] Specify whether to share indexes between different workspaces. Defaults to auto and the shared indexes is automatically enabled in Visual Studio Code - Insiders. auto on off java.sharedIndexes.location: Specifies a common index location for all workspaces. See default values as follows: Windows: First use "$APPDATA\\.jdt\\index", or "~\\.jdt\\index" if it does not exist macOS: "~/Library/Caches/.jdt/index" Linux: First use "$XDG_CACHE_HOME/.jdt/index", or "~/.cache/.jdt/index" if it does not exist java.refactoring.extract.interface.replace: Specify whether to replace all the occurrences of the subtype with the new extracted interface. Defaults to true. java.import.maven.disableTestClasspathFlag : Enable/disable test classpath segregation. When enabled, this permits the usage of test resources within a Maven project as dependencies within the compile scope of other projects. Defaults to false. java.configuration.maven.defaultMojoExecutionAction : Specifies default mojo execution action when no associated metadata can be detected. Defaults to ignore. java.completion.lazyResolveTextEdit.enabled: [Experimental] Enable/disable lazily resolving text edits for code completion. Defaults to true. java.edit.validateAllOpenBuffersOnChanges: Specifies whether to recheck all open Java files for diagnostics when editing a Java file. Defaults to false. java.editor.reloadChangedSources: Specifies whether to reload the sources of the open class files when their source jar files are changed. Defaults to ask. ask: Ask to reload the sources of the open class files auto: Automatically reload the sources of the open class files manual: Manually reload the sources of the open class files java.edit.smartSemicolonDetection.enabled: Defines the smart semicolon detection. Defaults to false. java.configuration.detectJdksAtStart: Automatically detect JDKs installed on local machine at startup. If you have specified the same JDK version in java.configuration.runtimes, the extension will use that version first. Defaults to true. java.completion.collapseCompletionItems: Enable/disable the collapse of overloaded methods in completion items. Overrides java.completion.guessMethodArguments. Defaults to false. java.diagnostic.filter: Specifies a list of file patterns for which matching documents should not have their diagnostics reported (eg. '**/Foo.java'). java.search.scope: Specifies the scope which must be used for search operation like Find Reference Call Hierarchy Workspace Symbols java.jdt.ls.javac.enabled: [Experimental] Specify whether to enable Javac-based compilation in the language server. Requires running this extension with Java 24. Defaults to off. java.completion.engine: [Experimental] Select code completion engine. Defaults to ecj. java.references.includeDeclarations: Include declarations when finding references. Defaults to true java.jdt.ls.appcds.enabled : [Experimental] Enable Java AppCDS (Application Class Data Sharing) for improvements to extension activation. When set to auto, AppCDS will be enabled in Visual Studio Code - Insiders, and for pre-release versions. Semantic Highlighting Semantic Highlighting fixes numerous syntax highlighting issues with the default Java Textmate grammar. However, you might experience a few minor issues, particularly a delay when it kicks in, as it needs to be computed by the Java Language server, when opening a new file or when typing. Semantic highlighting can be disabled for all languages using the editor.semanticHighlighting.enabled setting, or for Java only using language-specific editor settings. Troubleshooting Check the status of the language tools on the lower right corner (marked with A on image below). It should show ready (thumbs up) as on the image below. You can click on the status and open the language tool logs for further information in case of a failure. status indicator Read the troubleshooting guide for collecting informations about issues you might encounter. Report any problems you face to the project. Contributing This is an open source project open to anyone. Contributions are extremely welcome! For information on getting started, refer to the CONTRIBUTING instructions. Continuous Integration builds can be installed from http://download.jboss.org/jbosstools/jdt.ls/staging/. Download the most recent java-<version>.vsix file and install it by following the instructions here. Stable releases are archived under http://download.jboss.org/jbosstools/static/jdt.ls/stable/. Also, you can contribute your own VS Code extension to enhance the existing features by following the instructions here. Feedback Have a question? Start a discussion on GitHub Discussions, File a bug in GitHub Issues, Chat with us on Gitter, Tweet us with other feedback. License EPL 2.0, See LICENSE for more information.
最新发布
09-21
### 功能特性 Java语言支持扩展为在Visual Studio Code中开发Java项目提供了丰富功能。支持智能代码补全,能根据上下文自动补全代码,提高开发效率。具备强大的代码导航功能,可快速定位到类、方法的定义处。还支持代码重构,如重命名变量、提取方法等,方便代码的维护和优化。此外,提供调试功能,可设置断点、单步执行等,对Java代码进行调试。 ### 安装配置 在Visual Studio Code中,打开扩展面板(可通过点击左侧边栏的扩展图标),在搜索框中输入“Java Extension Pack”,该扩展包包含了Java开发所需的多个核心扩展,点击安装即可。安装完成后,VS Code会自动检测系统中的Java环境。若未检测到或需要指定特定的Java版本,可在`settings.json`中配置`java.home`属性,指定Java JDK的安装路径。示例配置如下: ```json { "java.home": "C:\\Program Files\\Java\\jdk-11.0.12" } ``` ### 可用命令 通过命令面板(快捷键`Ctrl+Shift+P`或`Cmd+Shift+P`)可使用众多Java相关命令。例如,`Java: Create Java Project`用于创建新的Java项目;`Java: Open Java Language Server Log File`可打开Java语言服务器的日志文件,帮助排查问题;`Java: Organize Imports`能自动整理Java文件中的导入语句。 ### 支持的设置项 在`settings.json`中可进行多项Java相关设置。`java.completion.maxResults`可设置代码补全的最大结果数;`java.format.settings.url`可指定Java代码格式化的配置文件URL;`java.configuration.runtimes`可配置多个Java运行时环境。示例配置如下: ```json { "java.completion.maxResults": 50, "java.format.settings.url": "https://example.com/eclipse-java-google-style.xml", "java.configuration.runtimes": [ { "name": "JavaSE-11", "path": "C:\\Program Files\\Java\\jdk-11.0.12" }, { "name": "JavaSE-17", "path": "C:\\Program Files\\Java\\jdk-17.0.2" } ] } ``` ### 语义高亮 该扩展支持语义高亮,会根据代码的语义信息对不同元素应用不同的颜色。例如,类名、方法名、变量名等会有不同的颜色显示,增强代码的可读性。可在VS Code的主题设置中调整语义高亮的颜色。 ### 故障排除 若遇到Java语言支持扩展无法正常工作的情况,可先检查Java环境配置是否正确,确保`java.home`路径指向有效的JDK安装目录。查看Java语言服务器的日志文件,从中获取详细的错误信息。还可尝试重新安装扩展或更新到最新版本。 ### 贡献方式 开发者可通过GitHub参与扩展的开发。访问扩展的开源仓库,了解开发文档和贡献指南,提交代码变更、修复问题或提出新的功能建议。 ### 反馈途径 可在扩展的GitHub仓库中提交Issues,详细描述遇到的问题或提出改进建议。也可在VS Code的社区论坛中与其他开发者交流,获取帮助和反馈。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值