JavaRush /Java Blogu /Random-AZ /Ümumi proqramlaşdırma üslubuna dair bələdçi
pandaFromMinsk
Səviyyə
Минск

Ümumi proqramlaşdırma üslubuna dair bələdçi

Qrupda dərc edilmişdir
Bu məqalə “Qabaqcıl Java” akademik kursunun bir hissəsidir. Material obyektin yaradılması, rəqabət, seriallaşdırma, əks etdirmə və s. kimi “qabaqcıl” mövzuları əhatə edir. Kurs sizə Java texnikasını effektiv şəkildə mənimsəməyi öyrədəcək. Təfərrüatlar burada .
Məzmun
1. Giriş 2. Dəyişənlərin əhatə dairəsi 3. Sinif sahələri və yerli dəyişənlər 4. Metod arqumentləri və yerli dəyişənlər 5. Boks və qutudan çıxarılma 6. İnterfeyslər 7. Sətirlər 8. Adlandırma Konvensiyaları 9. Standart Kitabxanalar 10. Dəyişməzlik 11. Növbəti Test. 12. .. 13. Mənbə kodunu yükləyin
1. Giriş
Dərsliyin bu hissəsində biz Java-da yaxşı proqramlaşdırma üslubunun və cavab verən dizaynın ümumi prinsipləri haqqında müzakirəmizi davam etdirəcəyik. Biz bu prinsiplərdən bəzilərini təlimatın əvvəlki fəsillərində artıq görmüşük, lakin Java tərtibatçısının bacarıqlarını təkmilləşdirmək məqsədi ilə bir çox praktiki məsləhətlər veriləcəkdir.
2. Dəyişən əhatə dairəsi
Üçüncü hissədə (“Sinifləri və interfeysləri necə tərtib etməli”) əhatə dairəsi məhdudiyyətləri nəzərə alınmaqla, siniflərin və interfeyslərin üzvlərinə görünmə və əlçatanlığın necə tətbiq oluna biləcəyini müzakirə etdik. Bununla belə, metodun tətbiqində istifadə olunan yerli dəyişənləri hələ müzakirə etməmişik. Java dilində hər bir yerli dəyişənin, bir dəfə elan edildiyi zaman əhatə dairəsi var. Bu dəyişən elan edildiyi yerdən metodun (və ya kod blokunun) icrasının tamamlandığı nöqtəyə qədər görünür. Ümumiyyətlə, riayət edilməli olan yeganə qayda yerli dəyişəni onun istifadə olunacağı yerə mümkün qədər yaxın elan etməkdir. Tipik bir misala baxım: for( final Locale locale: Locale.getAvailableLocales() ) { // блок codeа } try( final InputStream in = new FileInputStream( "file.txt" ) ) { // блока codeа } Hər iki kod fraqmentində dəyişənlərin əhatə dairəsi bu dəyişənlərin elan olunduğu icra blokları ilə məhdudlaşır. Blok tamamlandıqda əhatə dairəsi bitir və dəyişən görünməz olur. Bu, daha aydın görünür, lakin Java 8-in buraxılması və lambdaların tətbiqi ilə yerli dəyişənlərdən istifadə edən dilin bir çox tanınmış deyimləri köhnəlir. İcazə verin, əvvəlki misaldan dövrə əvəzinə lambdalardan istifadə edərək misal verim: Arrays.stream( Locale.getAvailableLocales() ).forEach( ( locale ) -> { // блок codeа } ); Siz görə bilərsiniz ki, lokal dəyişən funksiya üçün arqumentə çevrilib və bu da öz növbəsində forEach metoduna arqument kimi ötürülür .
3. Sinif sahələri və lokal dəyişənlər
Java-da hər bir metod müəyyən bir sinfə aiddir (yaxud Java8 vəziyyətində metodun standart metod kimi elan edildiyi interfeys). Bir sinifin sahələri olan və ya həyata keçirilməsində istifadə olunan metodlar olan yerli dəyişənlər arasında ad konfliktinin belə bir ehtimalı var. Java tərtibçisi mövcud dəyişənlər arasından düzgün dəyişəni necə seçəcəyini bilir, baxmayaraq ki, birdən çox tərtibatçı həmin dəyişəni istifadə etmək niyyətindədir. Müasir Java İDE-ləri tərtibçiyə kompilyator xəbərdarlıqları və dəyişənlərin vurğulanması vasitəsilə bu cür münaqişələrin nə vaxt baş verəcəyini bildirmək üçün əla iş görür. Amma yenə də kod yazarkən belə şeylər haqqında düşünmək daha yaxşıdır. Mən bir nümunəyə baxmağı təklif edirəm: public class LocalVariableAndClassMember { private long value; public long calculateValue( final long initial ) { long value = initial; value *= 10; value += value; return value; } } Nümunə olduqca asan görünür, lakin bu, tələdir. HesablamaValue metodu yerli dəyişən dəyəri təqdim edir və onun üzərində işləyərək eyni adlı sinif sahəsini gizlədir. Xətt value += value; sinif sahəsinin və yerli dəyişənin dəyərinin cəmi olmalıdır, lakin bunun əvəzinə başqa bir şey edilir. Düzgün həyata keçirmə belə görünəcək (bu açar sözündən istifadə etməklə): public class LocalVariableAndClassMember { private long value; public long calculateValue( final long initial ) { long value = initial; value *= 10; value += this.value; return value; } } Bu nümunə bəzi mənalarda sadəlövh olsa da, bəzi hallarda sazlama və düzəltmək üçün saatlar çəkə biləcəyi vacib bir məqamı nümayiş etdirir.
4. Metod arqumentləri və lokal dəyişənlər
Təcrübəsiz Java tərtibatçılarının tez-tez düşdüyü başqa bir tələ metod arqumentlərindən yerli dəyişənlər kimi istifadə etməkdir. Java sizə dəyərləri qeyri-sabit arqumentlərə yenidən təyin etməyə imkan verir (lakin bunun orijinal dəyərə heç bir təsiri yoxdur): public String sanitize( String str ) { if( !str.isEmpty() ) { str = str.trim(); } str = str.toLowerCase(); return str; } Yuxarıdakı kod parçası zərif deyil, lakin problemi aşkar etmək üçün yaxşı işləyir: str fərqli təyin olunur . dəyər (və əsasən yerli dəyişən kimi istifadə olunur) . Bütün hallarda (istisnasız) bu misal olmadan edə bilərsiniz və etməlisiniz (məsələn, arqumentləri sabitlər kimi elan etməklə). Məsələn: public String sanitize( final String str ) { String sanitized = str; if( !str.isEmpty() ) { sanitized = str.trim(); } sanitized = sanitized.toLowerCase(); return sanitized; } Bu sadə qaydaya əməl etməklə, hətta yerli dəyişənləri təqdim edərkən belə, verilmiş kodu izləmək və problemin mənbəyini tapmaq daha asandır.
5. Qablaşdırma və qablaşdırma
Boxing and unboxing Java-da primitiv növləri ( int, long, double və s. ) müvafiq tip sarğılara ( Tam, Uzun, Double və s. ) çevirmək üçün istifadə olunan texnikanın adıdır . Generikləri Necə və Nə Zaman İstifadə etməli təlimatının 4-cü Hissəsində mən ibtidai tipləri generiklərin tip parametrləri kimi bükmək haqqında danışarkən bunu artıq gördünüz. Java tərtibçisi avtoboksinq həyata keçirməklə bu cür çevrilmələri gizlətmək üçün əlindən gələni etsə də, bəzən bu, gözləniləndən az olur və gözlənilməz nəticələr verir. Bir misala baxaq: public static void calculate( final long value ) { // блок codeа } final Long value = null; calculate( value ); Yuxarıdakı kod parçası yaxşı tərtib edir. Bununla belə, Longlong arasında çevrildiyi xəttə NullPointerException atacaq . Belə bir iş üçün məsləhət odur ki, ibtidai növlərdən istifadə etmək məsləhətdir (lakin bunun həmişə mümkün olmadığını artıq bilirik). // блок
6. İnterfeyslər
Dərsliyin 3-cü hissəsində “Sinifləri və İnterfeysləri Necə Dizayn Etmək olar” adlı bölmədə biz interfeysləri və müqavilə proqramlaşdırmasını müzakirə etdik, mümkün olduqda interfeyslərə konkret siniflərə üstünlük verilməli olduğunu vurğuladıq. Bu bölmənin məqsədi real dünya nümunələri ilə bunu nümayiş etdirməklə ilk növbədə interfeysləri nəzərdən keçirməyə təşviq etməkdir. İnterfeyslər xüsusi bir tətbiqə bağlı deyil (standart üsullar istisna olmaqla). Onlar yalnız müqavilələrdir və məsələn, müqavilələrin icrasında çoxlu sərbəstlik və çeviklik təmin edir. Tətbiq xarici sistemlər və ya xidmətləri əhatə etdikdə bu çeviklik daha vacib olur. Sadə interfeys nümunəsinə və onun mümkün həyata keçirilməsinə baxaq: public interface TimezoneService { TimeZone getTimeZone( final double lat, final double lon ) throws IOException; } public class TimezoneServiceImpl implements TimezoneService { @Override public TimeZone getTimeZone(final double lat, final double lon) throws IOException { final URL url = new URL( String.format( "http://api.geonames.org/timezone?lat=%.2f&lng=%.2f&username=demo", lat, lon ) ); final HttpURLConnection connection = ( HttpURLConnection )url.openConnection(); connection.setRequestMethod( "GET" ); connection.setConnectTimeout( 1000 ); connection.setReadTimeout( 1000 ); connection.connect(); int status = connection.getResponseCode(); if (status == 200) { // Do something here } return TimeZone.getDefault(); } } Yuxarıdakı kod parçası tipik interfeys nümunəsini və onun həyata keçirilməsini göstərir. Bu tətbiq müəyyən məkanın saat qurşağını əldə etmək üçün xarici HTTP xidmətindən ( http://api.geonames.org/ ) istifadə edir. Lakin, çünki müqavilə interfeysdən asılıdır, məsələn, verilənlər bazası və ya hətta adi düz fayldan istifadə edərək interfeysin başqa bir tətbiqini təqdim etmək çox asandır. Onlarla interfeyslər sınaqdan keçirilə bilən kodun dizaynında çox faydalıdır. Məsələn, hər testdə xarici xidmətlərə zəng etmək həmişə praktiki deyil, ona görə də əvəzinə alternativ, ən sadə tətbiqi (məsələn, stub kimi) həyata keçirmək mənasızdır: Bu tətbiq TimezoneService interfeysinin tələb olunduğu public class TimezoneServiceTestImpl implements TimezoneService { @Override public TimeZone getTimeZone(final double lat, final double lon) throws IOException { return TimeZone.getDefault(); } } hər yerdə istifadə oluna bilər . skripti xarici komponentlərdən asılılıqdan sınayın. Bu cür interfeyslərdən səmərəli istifadənin bir çox gözəl nümunələri Java standart kitabxanasında əhatə olunmuşdur. Kolleksiyalar, siyahılar, dəstlər - bu interfeyslərin çoxlu tətbiqetmələri var ki, onlar problemsiz şəkildə dəyişdirilə bilər və müqavilələr üstünlük əldə etdikdə dəyişdirilə bilər. Misal üçün: public static< T > void print( final Collection< T > collection ) { for( final T element: collection ) { System.out.println( element ); } } print( new HashSet< Object >( /* ... */ ) ); print( new ArrayList< Integer >( /* ... */ ) ); print( new TreeSet< String >( /* ... */ ) );
7. Simlər
Sətirlər həm Java, həm də digər proqramlaşdırma dillərində ən çox istifadə edilən növlərdən biridir. Java dili konkatenasiya və müqayisə əməliyyatlarını dərhal dəstəkləməklə bir çox adi sətir manipulyasiyalarını asanlaşdırır. Bundan əlavə, standart kitabxanada sətir əməliyyatlarını səmərəli edən bir çox sinif var. Bu bölmədə müzakirə edəcəyimiz şey məhz budur. Java-da sətirlər UTF-16 kodlaşdırmasında təmsil olunan dəyişməz obyektlərdir. Hər dəfə sətirləri birləşdirəndə (və ya orijinal sətri dəyişdirən hər hansı əməliyyatı yerinə yetirdikdə), String sinifinin yeni nümunəsi yaradılır . Buna görə birləşdirmə əməliyyatı çox səmərəsiz ola bilər və String sinifinin bir çox aralıq nümunələrinin yaradılmasına səbəb ola bilər (ümumiyyətlə zibil yaratmaq). Lakin Java standart kitabxanasında məqsədi simli manipulyasiyanı rahat etmək olan iki çox faydalı sinif var. Bunlar StringBuilderStringBuffer- dir (aralarındakı yeganə fərq StringBuffer-in iplə təhlükəsiz olması, StringBuilder isə əksinə olmasıdır). İstifadə olunan bu siniflərdən birinin bir neçə nümunəsinə baxaq: StringBuilder/StringBuffer- final StringBuilder sb = new StringBuilder(); for( int i = 1; i <= 10; ++i ) { sb.append( " " ); sb.append( i ); } sb.deleteCharAt( 0 ); sb.insert( 0, "[" ); sb.replace( sb.length() - 3, sb.length(), "]" ); dan istifadə sətirləri manipulyasiya etmək üçün tövsiyə edilən üsul olsa da, iki və ya üç sətir birləşdirən ən sadə ssenaridə o, həddindən artıq görünə bilər ki, normal əlavə operatoru ( ( "+"), məsələn: Tez-tez birləşməni sadələşdirmək üçün ən yaxşı alternativ statik String.format köməkçi metodunu təmin etmək üçün sətir formatlaşdırma və Java Standart Kitabxanasından istifadə etməkdir . Bu, nömrələr, simvollar, tarix/saat və s. daxil olmaqla zəngin format təyinedicilər dəstini dəstəkləyir. (Tam təfərrüatlar üçün istinad sənədlərinə baxın) String.format metodu müxtəlif məlumat növlərindən sətirlər yaratmaq üçün təmiz və yüngül yanaşma təmin edir. Qeyd etmək lazımdır ki, müasir Java İDE-ləri String.format metoduna ötürülən arqumentlərdən format spesifikasiyasını təhlil edə və hər hansı uyğunsuzluq aşkar edildikdə tərtibatçıları xəbərdar edə bilər. String userId = "user:" + new Random().nextInt( 100 ); String.format( "%04d", 1 ); -> 0001 String.format( "%.2f", 12.324234d ); -> 12.32 String.format( "%tR", new Date() ); -> 21:11 String.format( "%tF", new Date() ); -> 2014-11-11 String.format( "%d%%", 12 ); -> 12%
8. Adlandırma qaydaları
Java tərtibatçıları hər hansı bir adlandırma konvensiyasına ciddi şəkildə riayət etməyə məcbur etməyən bir dildir, lakin icma Java kodunu həm standart kitabxanada, həm də hər hansı digər Java layihələrində ardıcıl görünməsini təmin edən bir sıra sadə qaydalar hazırlayıb:
  • paket adları kiçik hərflərlə yazılmışdır: org.junit, com.fasterxml.jackson, javax.json
  • siniflərin adları, siyahılar, interfeyslər, annotasiyalar böyük hərflə yazılır: StringBuilder, Runnable, @Override
  • sahələrin və ya metodların adları ( statik final istisna olmaqla ) dəvə qeydində göstərilir: isEmpty, format, addAll
  • statik yekun sahə və ya sadalama sabiti adları böyük hərflə yazılmışdır, alt xətt ("_") ilə ayrılmışdır: LOG, MIN_RADIX, INSTANCE.
  • yerli dəyişənlər və ya metod arqumentləri dəvə qeydində yazılır: str, newLength, minimumCapacity
  • generiklər üçün parametr tipi adları böyük hərfdə tək hərflə təmsil olunur: T, U, E
Bu sadə konvensiyalara əməl etməklə, yazdığınız kod qısa və üslub baxımından başqa kitabxana və ya çərçivədən fərqlənməyəcək və eyni şəxs tərəfindən işlənib hazırlanmış kimi hiss olunacaq (konvensiyaların həqiqətən işlədiyi nadir hallardan biri).
9. Standart kitabxanalar
Hansı Java layihəsi üzərində işlədiyinizdən asılı olmayaraq, Java standart kitabxanaları sizin ən yaxşı dostlarınızdır. Bəli, onların bəzi kobud kənarları və qəribə dizayn qərarları olması ilə razılaşmamaq çətindir, lakin 99% hallarda bu, mütəxəssislər tərəfindən yazılmış yüksək keyfiyyətli koddur. Kəşf etməyə dəyər. Hər bir Java buraxılışı mövcud kitabxanalara bir çox yeni funksiyalar gətirir (köhnə funksiyalarla bağlı bəzi mümkün problemlərlə) və həmçinin bir çox yeni kitabxanalar əlavə edir. Java 5, java.util.concurrent paketinin bir hissəsi kimi yeni paralellik kitabxanası gətirdi . Java 6 (daha az tanınmış) skript dəstəyi ( javax.script paketi) və Java kompilyator API ( javax.tools paketinin bir hissəsi kimi ) təqdim etdi. Java 7 java.util.concurrent -ə bir çox təkmilləşdirmələr gətirdi, java.nio.file paketində yeni I/O kitabxanası və java.lang.invoke -da dinamik dillərə dəstək təqdim etdi . Və nəhayət, Java 8 çoxdan gözlənilən tarixi/saatı java.time paketinə əlavə etdi . Java bir platforma olaraq inkişaf edir və onun yuxarıdakı dəyişikliklərlə birlikdə irəliləməsi çox vacibdir. Layihənizə üçüncü tərəf kitabxanasını və ya çərçivəsini daxil etməyi düşündüyünüz zaman, tələb olunan funksionallığın artıq standart Java kitabxanalarında olmadığına əmin olun (əlbəttə ki, alqoritmlərin bir çox ixtisaslaşdırılmış və yüksək performanslı tətbiqləri var. standart kitabxanalarda alqoritmlər var, lakin əksər hallarda onlar həqiqətən lazım deyil).
10. Dəyişməzlik
Bələdçi boyunca və bu hissədə dəyişməzlik bir xatırlatma olaraq qalır: lütfən, bunu ciddi qəbul edin. Əgər dizayn etdiyiniz sinif və ya tətbiq etdiyiniz üsul dəyişməzlik zəmanəti verə bilirsə, o, eyni zamanda dəyişdirilməkdən qorxmadan əksər hallarda hər yerdə istifadə edilə bilər. Bu, bir tərtibatçı kimi həyatınızı (və ümid edirəm ki, komanda üzvlərinizin həyatını) asanlaşdıracaq.
11. Sınaq
Test əsaslı inkişaf (TDD) təcrübəsi Java cəmiyyətində son dərəcə populyardır və kod keyfiyyəti üçün zolağı artırır. TDD-nin təmin etdiyi bütün üstünlüklərə baxmayaraq, bu gün Java standart kitabxanasının heç bir test çərçivəsi və ya dəstək alətləri olmadığını görmək kədərlidir. Bununla belə, sınaq müasir Java inkişafının zəruri hissəsinə çevrilib və bu bölmədə biz JUnit çərçivəsindən istifadə edən bir neçə əsas texnikaya baxacağıq . JUnit-də, mahiyyətcə, hər bir test obyektin gözlənilən vəziyyəti və ya davranışı haqqında ifadələr toplusudur. Mükəmməl testlər yazmağın sirri onları sadə və qısa saxlamaq, hər dəfə bir şeyi sınamaqdır. Bir məşq olaraq, String.formatın string bölməsindən istənilən nəticəni qaytaran funksiya olduğunu yoxlamaq üçün bir sıra testlər yazaq . package com.javacodegeeks.advanced.generic; import static org.junit.Assert.assertThat; import static org.hamcrest.CoreMatchers.equalTo; import org.junit.Test; public class StringFormatTestCase { @Test public void testNumberFormattingWithLeadingZeros() { final String formatted = String.format( "%04d", 1 ); assertThat( formatted, equalTo( "0001" ) ); } @Test public void testDoubleFormattingWithTwoDecimalPoints() { final String formatted = String.format( "%.2f", 12.324234d ); assertThat( formatted, equalTo( "12.32" ) ); } } Hər iki test çox oxunaqlı görünür və onların icrası nümunələrdir. Bu gün orta Java layihəsi yüzlərlə sınaq nümunəsini ehtiva edir və inkişaf etdiriciyə reqressiyalar və ya xüsusiyyətlər haqqında inkişaf prosesi zamanı tez rəy verir.
12. Sonrakı
Bələdçinin bu hissəsi Java-da proqramlaşdırma təcrübəsi ilə bağlı bir sıra müzakirələri və bu proqramlaşdırma dili üçün təlimatları tamamlayır. Növbəti dəfə biz istisnalar, onların növləri, onlardan necə və nə vaxt istifadə ediləcəyi ilə bağlı Java dünyasını araşdıraraq dilin xüsusiyyətlərinə qayıdacağıq.
13. Mənbə kodunu yükləyin
Bu Advanced Java kursundan ümumi inkişaf prinsipləri haqqında bir dərs idi. Dərsin mənbə kodunu buradan yükləmək olar .
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION