日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何有效地编写方法

發布時間:2023/12/3 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何有效地编写方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文是我們名為“ 高級Java ”的學院課程的一部分。

本課程旨在幫助您最有效地使用Java。 它討論了高級主題,包括對象創建,并發,序列化,反射等。 它將指導您完成Java掌握的過程! 在這里查看 !

目錄

1.簡介 2.方法簽名 3.方法主體 4.方法重載 5.方法覆蓋 6.內聯 7.遞歸 8.方法參考 9.不變性 10.方法文檔 11.方法參數和返回值 12.方法作為API入口點 13.接下來是什么 14.下載源代碼

1.簡介

在本教程的這一部分中,我們將花費一些時間來討論與Java設計和實現方法有關的不同方面。 正如我們在本教程的前面部分所看到的那樣,用Java編寫方法非常容易,但是有很多事情可以使您的方法更具可讀性和效率。

2.方法簽名

眾所周知,Java是一種面向對象的語言。 這樣,Java中的每個方法都屬于某個類實例(如果使用static方法,則屬于一個類本身),具有可見性(或可訪問性)規則,可以聲明為abstract或final等。 但是,可以說方法的最重要部分是它的簽名:返回類型和參數,以及方法實現可能拋出的已檢查異常的列表(但是如今,這一部分的使用越來越少了)。 下面是一個小例子:

public static void main( String[] args ) {// Some implementation here }

main方法將字符串數組作為唯一參數args接受,并且不返回任何內容。 使所有方法保持與main一樣簡單將是非常好的。 但實際上,方法簽名可能變得不可讀。 讓我們看下面的例子:

public void setTitleVisible( int lenght, String title, boolean visible ) {// Some implementation here }

首先要注意的是,按照慣例,Java中的方法名稱以駝峰形式編寫,例如: setTitleVisible 。 該名稱選擇得當,并試圖描述該方法應該執行的操作。

其次,每個參數的名稱說明(或至少暗示)其目的。 為方法參數找到正確的解釋性名稱非常重要,而不是int i , String s , boolean f (但是在極少數情況下還是有意義的)。

第三,該方法僅接受三個參數。 盡管Java對允許的參數數量有更高的限制,但強烈建議將此數字保持在6以下。除此之外,方法簽名變得很難理解。

從Java 5發行版開始,這些方法可以使用特殊語法具有相同類型的參數變量列表(稱為varargs),例如:

public void find( String ... elements ) {// Some implementation here }

在內部,Java編譯器將varargs轉換為相應類型的數組,這就是方法實現可以訪問varargs的方式。

有趣的是,Java還允許使用泛型類型參數聲明varargs參數。 但是,由于參數的類型未知,因此Java編譯器希望確保負責任地使用varargs ,并建議該方法是final并使用@SafeVarargs批注進行批注(有關批注的更多詳細信息,請參見第5部分)。教程, 以及如何以及何時使用Enums和Annotations )。 例如:

@SafeVarargs final public< T > void find( T ... elements ) {// Some implementation here }

另一種方法是使用@SuppressWarnings批注,例如:

@SuppressWarnings( "unchecked" ) public< T > void findSuppressed( T ... elements ) {// Some implementation here }

下一個示例演示將檢查的異常用作方法簽名的一部分。 近年來,事實證明,已檢查的異常不如預期的那樣有用,導致編寫更多的樣板代碼而不是解決的問題。

public void write( File file ) throws IOException {// Some implementation here }

最后但并非最不重要的一點是,通常建議(但很少使用)將方法參數標記為final 。 當用不同的值重新分配方法參數時,它有助于擺脫不良的代碼實踐。 同樣,匿名類可以使用這種方法參數(有關匿名類的更多詳細信息,在本教程的第3部分“ 如何設計類和接口”中進行了介紹 ),盡管Java 8通過有效地引入final變量來緩解了這一限制。

3.方法主體

每種方法都有其自己的實現和目的。 但是,有一些通用指南確實可以幫助編寫清晰易懂的方法。

可能最重要的一個是單一責任原則:嘗試以這種方式實現方法,即每個單一方法都只會做一件事情并且做得很好。 遵循此原理可能會炸毀許多類方法,因此找到合適的平衡很重要。

編碼和設計時的另一重要事項是保持方法實現的簡短(通常只需遵循單一職責原則,您就可以免費獲得它)。 簡短的方法很容易推論,而且它們通常適合一個屏幕,因此您的代碼讀者可以更快地理解它們。

最后(但并非最不重要)的建議與使用return語句有關。 如果某個方法返回某個值,請嘗試最大程度地減少調用return語句的位置(有些人走得更遠,建議在所有情況下僅使用單個return語句)。 更多的return語句方法變得很難遵循其邏輯流程并修改(或重構)實現。

4.方法重載

方法重載技術通常用于為不同的參數類型或組合提供方法的專用版本。 盡管方法名稱保持不變,但是編譯器會根據調用點的實際參數值選擇正確的替代方法(重載的最佳示例是Java中的構造函數:名稱始終相同,但參數集不同)或如果找不到,將引發編譯器錯誤。 例如:

public String numberToString( Long number ) {return Long.toString( number ); }public String numberToString( BigDecimal number ) {return number.toString(); }

方法重載在某種程度上接近于泛型(關于泛型的更多詳細信息在本教程的第4部分“ 如何以及何時使用泛型”中進行了介紹 ),但是它在泛型方法不能很好地工作并且每種(或大多數)泛型使用的情況下使用類型參數需要它們自己的專用實現。 盡管如此,將泛型和重載結合起來可能非常強大,但是由于類型擦除(在Java中通常是不可能的)(有關更多詳細信息,請參閱教程的第4部分如何及何時使用泛型 )。 讓我們看一下這個例子:

public< T extends Number > String numberToString( T number ) {return number.toString(); }public String numberToString( BigDecimal number ) {return number.toPlainString(); }

盡管可以在不使用泛型的情況下編寫此代碼段,但對于我們的演示目的而言,它不是重要的。 有趣的是,方法numberToString重載了BigDecimal的專門實現,并為所有其他數字提供了通用版本。

5.方法覆蓋

在本教程的第3部分“ 如何設計類和接口”中 ,我們討論了很多方法重寫。 在本節中,當我們已經知道方法重載時,我們將展示為什么使用@Override批注如此重要。 我們的示例將演示簡單類層次結構中方法重寫和重載之間的細微差別。

public class Parent {public Object toObject( Number number ) {return number.toString();} }

Parent類只有一個toObject方法。 讓我們對該類進行子類化,并嘗試提出方法版本以將數字轉換為字符串(而不是原始對象)。

public class Child extends Parent {@Overridepublic String toObject( Number number ) {return number.toString();} }

盡管如此, Child類中toObject方法的簽名還是有些不同(請參見Covariant方法返回類型以獲取更多詳細信息),它確實覆蓋了超類中的那個,并且Java編譯器對此沒有任何抱怨。 現在,讓我們向Child類添加另一個方法。

public class Child extends Parent {public String toObject( Double number ) {return number.toString();} }

同樣,方法簽名之間只有細微的差別(用Double代替Number ),但是在這種情況下,它是方法的重載版本,它不會覆蓋父方法。 這就是Java編譯器和@Override注釋的幫助得到回報的時候:用@Override注釋上一個示例中的方法會引發編譯器錯誤。

6.內聯

內聯是Java JIT(即時)編譯器執行的優化,目的是消除特定的方法調用并將其直接替換為方法實現。 JIT編譯器使用的啟發式方法取決于方法的調用頻率和大小。 太大的方法不能有效地內聯。 內聯可以大大提高代碼的性能,這是使方法保持簡短的另一個好處,如我們在“ 方法正文 ”一節中所討論的。

7.遞歸

Java中的遞歸是一種方法,該方法在執行計算時會調用自身。 例如,讓我們看下面的示例,該示例求和一個數組的數字:

public int sum( int[] numbers ) {if( numbers.length == 0 ) {return 0;} if( numbers.length == 1 ) {return numbers[ 0 ];} else {return numbers[ 0 ] + sum( Arrays.copyOfRange( numbers, 1, numbers.length ) );} }

這是一個非常無效的實現,但是它很好地證明了遞歸。 遞歸方法存在一個眾所周知的問題:根據調用鏈的深度,它們可能會炸毀堆棧并導致StackOverflowError異常。 但是事情并沒有聽起來那么糟糕,因為有一種技術可以消除棧溢出,稱為尾部調用優化 。 如果方法是尾部遞歸的,則可以應用此方法(尾部遞歸方法是所有遞歸調用都是尾部調用的方法)。 例如,讓我們以尾遞歸的方式重寫以前的算法:

public int sum( int initial, int[] numbers ) {if( numbers.length == 0 ) {return initial;} if( numbers.length == 1 ) {return initial + numbers[ 0 ];} else {return sum( initial + numbers[ 0 ],Arrays.copyOfRange( numbers, 1, numbers.length ) );} }

不幸的是,目前Java編譯器(以及JVM JIT編譯器)不支持尾部調用優化,但是當您用Java編寫遞歸算法時,它仍然是了解和考慮的一種非常有用的技術。

8.方法參考

通過將功能性概念引入Java語言,Java 8向前邁出了一大步。 其基礎是將方法視為數據,這是該語言以前所不支持的概念(但是,由于Java 7,JVM和Java標準庫已經具有使之成為可能的某些功能)。 幸運的是,有了方法引用,現在就可以了。

參考類型
引用靜態方法 SomeClass::staticMethodName
引用特定對象的實例方法 someInstance::instanceMethodName
引用特定類型的任意對象的實例方法 SomeType::methodName
引用構造函數 SomeClass::new

表格1

讓我們看一個簡單的示例,該示例說明如何將方法作為參數傳遞給其他方法。

public class MethodReference {public static void println( String s ) {System.out.println( s );}public static void main( String[] args ) {final Collection< String > strings = Arrays.asList( "s1", "s2", "s3" );strings.stream().forEach( MethodReference::println );} }

main方法的最后一行使用對println方法的引用將字符串集合中的每個元素打印到控制臺,并將其作為參數傳遞給另一個方法forEach 。

9.不變性

如今,不變性已引起了很多關注,Java也不例外。 眾所周知,不變性在Java中很難實現,但這并不意味著應將其忽略。

在Java中,不變性就是改變內部狀態。 作為示例,讓我們看一下JavaBeans規范( http://docs.oracle.com/javase/tutorial/javabeans/ )。 它非常清楚地表明,setter可以修改包含對象的狀態,而這正是每個Java開發人員所期望的。

但是,替代方法不是修改狀態,而是每次都返回一個新狀態。 它并不像聽起來那樣可怕,新的Java 8 Date / Time API (在JSR 310:Date and Time API框架下開發)就是一個很好的例子。 讓我們看一下以下代碼片段:

final LocalDateTime now = LocalDateTime.now(); final LocalDateTime tomorrow = now.plusHours( 24 );final LocalDateTime midnight = now.withHour( 0 ).withMinute( 0 ).withSecond( 0 ).withNano( 0 );

每次需要修改其狀態的LocalDateTime實例調用都將返回新的LocalDateTime實例,并使原始實例保持不變。 與舊的Calendar和Date相比,API設計范例發生了很大的變化(使用起來不太舒服,并且引起很多麻煩)。

10.方法文檔

在Java中,特別是如果您正在開發某種庫或框架,則應使用Javadoc工具記錄所有公共方法( http://www.oracle.com/technetwork/articles/java/index-jsp-135444.html ) 。 嚴格來說,沒有什么可以強迫您執行此操作,但是好的文檔可以幫助其他開發人員了解特定方法的作用,所需的參數,其實現所具有的假設或約束,異常的類型以及何時可以引發以及返回值(如果有)可能是(加上更多東西)。

讓我們看下面的例子:

/*** The method parses the string argument as a signed decimal integer.* The characters in the string must all be decimal digits, except* that the first character may be a minus sign {@code '-'} or plus* sign {@code '+'}.** <p>An exception of type {@code NumberFormatException} is thrown if* string is {@code null} or has length of zero.** <p>Examples:* <blockquote><pre>* parse( "0" ) returns 0* parse( "+42") returns 42* parse( "-2" ) returns -2* parse( "string" ) throws a NumberFormatException* </pre></blockquote>** @param str a {@code String} containing the {@code int} representation to be parsed* @return the integer value represented by the string* @exception NumberFormatException if the string does not contain a valid integer value*/ public int parse( String str ) throws NumberFormatException {return Integer.parseInt( str ); }

對于parse這樣的簡單方法,它是一個非常冗長的文檔,但是它展示了Javadoc工具提供的一些有用功能,包括對其他類的引用,示例代碼片段和高級格式化。 這是流行的Java IDE之一Eclipse反映此方法文檔的方式。

僅通過查看上面的圖片,任何初級到高級的Java開發人員都可以了解該方法的目的以及使用該方法的正確方法。

11.方法參數和返回值

文檔化方法是一件很了不起的事情,但是不幸的是,當使用不正確或意外的參數值調用方法時,它不能阻止用例。 因此,根據經驗,所有公共方法都應驗證其自變量,并且永遠不應相信將始終使用正確的值來指定它們(這種模式稱為健全性檢查)。

回到上一節的示例,方法parse應該在對其執行任何操作之前執行其唯一參數的驗證:

public int parse( String str ) throws NumberFormatException {if( str == null ) {throw new IllegalArgumentException( "String should not be null" );}return Integer.parseInt( str ); }

Java還有另一個選擇可以使用assert語句執行驗證和健全性檢查。 但是,可以在運行時將其關閉,并且可能無法執行。 最好始終執行此類檢查并提出相關異常。

即使已經記錄了方法并驗證了它們的參數,仍然有一些與它們可以返回的值有關的注釋。 在Java 8之前,說“我目前沒有值”的方法的最簡單方法就是返回null 。 這就是Java對于NullPointerException異常如此臭名昭著的原因。 Java 8試圖通過引入Optional < T >類來解決此問題。 讓我們看一下這個例子:

public< T > Optional< T > find( String id ) {// Some implementation here }

Optional < T >提供了許多有用的方法,并且完全消除了該方法返回null并在各處使用null檢查污染代碼的需要。 唯一的例外可能是集合。 每當方法返回集合時,總是最好返回空的而不是null (甚至是Optional < T > ),例如:

public&lt; T &gt; Collection&lt; T &gt; find( String id ) { return Collections.emptyList(); }

12.方法作為API入口點

即使您只是在組織內構建應用程序的開發人員,還是對流行的Java框架或庫之一的貢獻者,您正在執行的設計決策在如何使用代碼方面都起著非常重要的作用。

盡管API設計指南值得多本書籍,但本教程的這一部分涉及其中的許多內容(因為方法成為API的切入點),因此快速總結將非常有幫助:

  • 為方法及其參數使用有意義的名稱( 方法簽名 )
  • 嘗試使參數的數量小于6(“ 方法簽名”部分)
  • 保持方法簡短易讀(“ 方法主體”和“ 內聯”一節)
  • 始終記錄您的公共方法,包括前提條件和示例(如果有必要的話)(“ 方法文檔”部分)
  • 始終執行參數驗證和完整性檢查(“ 方法參數和返回值”部分 )
  • 嘗試轉義null作為方法的返回值(“ 方法參數和返回值”部分 )
  • 每當它是有道理的,嘗試設計不變的方法(這不影響內部狀態,部分不變性 )
  • 使用可見性和可訪問性規則隱藏不應該公開的方法(本教程的第3部分如何設計類和接口

13.接下來是什么

本教程的這一部分討論的不是Java語言,而是更多關于如何有效地使用Java語言,特別是通過編寫可讀,干凈,有文檔的有效方法。 在下一節中,我們將繼續相同的基本思想,并討論通用的編程準則,以幫助您成為更好的Java開發人員。

14.下載源代碼

這是關于如何有效地編寫方法的課程。 您可以在此處下載源代碼: advanced-java-part-6

翻譯自: https://www.javacodegeeks.com/2015/09/how-to-write-methods-efficiently.html

總結

以上是生活随笔為你收集整理的如何有效地编写方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。