JavaRush /Java блогы /Random-KK /Жалпы бағдарламалау стилі бойынша нұсқаулық
pandaFromMinsk
Деңгей
Минск

Жалпы бағдарламалау стилі бойынша нұсқаулық

Топта жарияланған
Бұл мақала «Жетілдірілген Java» академиялық курсының бөлігі болып табылады. Бұл курс Java мүмкіндіктерін тиімді пайдалануды үйренуге көмектесу үшін жасалған. Материал an object құру, бәсекелестік, сериялау, рефлексия және т.б. сияқты «ілгері» тақырыптарды қамтиды. Курс Java әдістерін тиімді меңгеруді үйретеді. Толық ақпарат осында .
Мазмұны
1. Кіріспе 2. Айнымалылар ауқымы 3. Класс өрістері және жергілікті айнымалылар 4. Әдіс аргументтері және жергілікті айнымалылар 5. Қораптау және қораптан шығару 6. Интерфейстер 7. Жолдар 8. Атау конвенциялары 9. Стандартты кітапханалар 10. Өзгермейтіндік 11. Келесі Тестілеу. 12. .. 13. Бастапқы codeты жүктеп алыңыз
1. Кіріспе
Оқулықтың осы бөлігінде біз Java тіліндегі жақсы бағдарламалау стилі мен жауапты дизайнның жалпы принциптерін талқылауды жалғастырамыз. Біз осы принциптердің кейбірін нұсқаулықтың алдыңғы тарауларында көрдік, бірақ Java әзірлеушісінің дағдыларын жақсарту мақсатында көптеген практикалық кеңестер беріледі.
2. Айнымалы ауқым
Үшінші бөлімде («Сыныптар мен интерфейстерді қалай жобалау керек») біз ауқым шектеулерін ескере отырып, сыныптар мен интерфейстер мүшелеріне көріну мен қол жетімділікті қалай қолдануға болатынын талқыладық. Дегенмен, біз әдісті іске асыруда қолданылатын жергілікті айнымалыларды әлі талқылаған жоқпыз. Java тілінде жарияланғаннан кейін әрбір жергілікті айнымалының қолдану аясы болады. Бұл айнымалы ол жарияланған жерден әдісті (немесе code блогын) орындау аяқталғанға дейін көрінетін болады. Жалпы, орындалатын жалғыз ереже - жергілікті айнымалыны ол қолданылатын жерге мүмкіндігінше жақын жариялау. Типтік мысалды қарастыруға рұқсат етіңіз: for( final Locale locale: Locale.getAvailableLocales() ) { // блок codeа } try( final InputStream in = new FileInputStream( "file.txt" ) ) { // блока codeа } Екі code фрагментінде де айнымалылардың ауқымы осы айнымалылар жарияланған орындау блоктарымен шектеледі. Блок аяқталғанда, ауқым аяқталады және айнымалы көрінбейтін болады. Бұл түсінікті болып көрінеді, бірақ Java 8 шығарылымымен және лямбдалардың енгізілуімен жергілікті айнымалы мәндерді қолданатын тілдегі белгілі идиомалардың көпшілігі ескіруде. Циклдың орнына ламбдаларды қолданатын алдыңғы мысалдан мысал келтірейін: Arrays.stream( Locale.getAvailableLocales() ).forEach( ( locale ) -> { // блок codeа } ); Жергілікті айнымалы функцияның аргументіне айналғанын көруге болады, ол өз кезегінде forEach әдісіне аргумент ретінде жіберіледі .
3. Класс өрістері және жергілікті айнымалылар
Java тіліндегі әрбір әдіс белгілі бір сыныпқа жатады (немесе Java8 жағдайында әдіс әдепкі әдіс ретінде жарияланған интерфейс). Класстың өрістері болып табылатын жергілікті айнымалылар немесе іске асыруда қолданылатын әдістер арасында атау қақтығыстарының осындай мүмкіндігі бар. Java компиляторы бірнеше әзірлеуші ​​осы айнымалы мәнді пайдаланғысы келсе де, қол жетімділердің ішінен дұрыс айнымалыны қалай таңдау керектігін біледі. Заманауи Java IDE-лері компилятордың ескертулері және айнымалыларды бөлектеу арқылы әзірлеушіге мұндай қақтығыстар қашан орын алатынын айтудың тамаша жұмысын атқарады. Бірақ codeты жазу кезінде мұндай нәрселер туралы ойлану әлі де жақсы. Мен мысалды қарауды ұсынамын: public class LocalVariableAndClassMember { private long value; public long calculateValue( final long initial ) { long value = initial; value *= 10; value += value; return value; } } Мысал өте оңай көрінеді, бірақ бұл тұзақ. AccountValue әдісі жергілікті айнымалы мәнді енгізеді және онымен жұмыс істей отырып, бірдей атпен класс өрісін жасырады. Жол value += value; сынып өрісі мен жергілікті айнымалы мәннің қосындысы болуы керек, бірақ оның орнына басқа нәрсе орындалуда. Тиісті іске асыру келесідей болады (this кілт сөзін пайдалану): public class LocalVariableAndClassMember { private long value; public long calculateValue( final long initial ) { long value = initial; value *= 10; value += this.value; return value; } } Бұл мысал кейбір жолдармен аңғал болса да, ол кейбір жағдайларда жөндеуге және түзетуге бірнеше сағат кетуі мүмкін маңызды нәрсені көрсетеді.
4. Әдіс аргументтері және жергілікті айнымалылар
Тәжірибесіз Java әзірлеушілері жиі кездесетін тағы бір қателік жергілікті айнымалылар ретінде әдіс аргументтерін пайдалану болып табылады. Java сізге мәндерді тұрақты емес аргументтерге қайта тағайындауға мүмкіндік береді (бірақ бұл бастапқы мәнге әсер етпейді): public String sanitize( String str ) { if( !str.isEmpty() ) { str = str.trim(); } str = str.toLowerCase(); return str; } Жоғарыдағы code үзіндісі талғампаз емес, бірақ ол мәселені ашуда жақсы жұмыс істейді: str аргументі тағайындалды басқа мән (және негізінен жергілікті айнымалы ретінде пайдаланылады) . Барлық жағдайларда (ешқандай ерекшеліксіз) сіз бұл мысалсыз жасай аласыз және істеу керек (мысалы, аргументтерді тұрақтылар ретінде жариялау арқылы). Мысалы: public String sanitize( final String str ) { String sanitized = str; if( !str.isEmpty() ) { sanitized = str.trim(); } sanitized = sanitized.toLowerCase(); return sanitized; } Осы қарапайым ережені орындау арқылы, тіпті жергілікті айнымалыларды енгізу кезінде де берілген codeты қадағалау және мәселенің көзін табу оңайырақ.
5. Орау және қаптамадан шығару
Boxing and unboxing — Java тілінде қарапайым түрлерді ( int , long, double , т. «Генериктерді қалай және қашан пайдалану керек» оқулығының 4-бөлімінде мен генериктердің тип параметрлері ретінде қарабайыр типтерді орау туралы айтқанымда, сіз мұны әрекетте көрдіңіз. Java компиляторы автобоксингті орындау арқылы мұндай түрлендірулерді барынша жасыруға тырысса да, кейде бұл күтілгеннен аз болады және күтпеген нәтижелер береді. Мысалды қарастырайық: public static void calculate( final long value ) { // блок codeа } final Long value = null; calculate( value ); Жоғарыдағы code үзіндісі жақсы құрастырылады. Дегенмен, ол Long және long арасында түрлендірілетін жолға NullPointerException жібереді . Мұндай жағдайға кеңес ретінде қарабайыр типтерді қолданған жөн (бірақ, бұл әрқашан мүмкін емес екенін білеміз). // блок
6. Интерфейстер
Оқу құралының 3-бөлімінде «Кластар мен интерфейстерді қалай жобалау керек» біз интерфейстер мен келісім-шарттық бағдарламалауды талқылап, интерфейстерге мүмкіндігінше нақты сыныптардан артықшылық беру керектігін атап өттік. Бұл бөлімнің мақсаты – өмірден алынған мысалдар арқылы көрсету арқылы интерфейстерді алдымен қарастыруға шақыру. Интерфейстер нақты іске асыруға байланысты емес (әдепкі әдістерден басқа). Олар тек келісім-шарттар болып табылады және мысал ретінде олар келісім-шарттарды орындау жолында үлкен еркіндік пен икемділік береді. Бұл икемділік енгізу сыртқы жүйелерді немесе қызметтерді қамтитын кезде маңыздырақ болады. Қарапайым интерфейстің мысалын және оның мүмкін орындалуын қарастырайық: 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(); } } Жоғарыдағы code үзіндісі типтік интерфейс үлгісін және оның орындалуын көрсетеді. Бұл іске асыру белгілі бір орынның уақыт белдеуін шығарып алу үшін сыртқы HTTP қызметін ( http://api.geonames.org/ ) пайдаланады. Алайда, өйткені келісім-шарт интерфейске байланысты, мысалы, дерекқорды немесе тіпті қарапайым жалпақ файлды пайдалана отырып, интерфейстің басқа іске асырылуын енгізу өте оңай. Олардың көмегімен интерфейстер сыналатын codeты жобалауда өте пайдалы. Мысалы, әрбір сынақта сыртқы қызметтерге қоңырау шалу әрқашан практикалық бола бермейді, сондықтан оның орнына балама, ең қарапайым іске асыруды (мысалы, стендті) енгізу мағынасы бар: Бұл іске қосу TimezoneService интерфейсі қажет public class TimezoneServiceTestImpl implements TimezoneService { @Override public TimeZone getTimeZone(final double lat, final double lon) throws IOException { return TimeZone.getDefault(); } } кез келген жерде пайдаланылуы мүмкін. сыртқы компоненттерге тәуелділіктен сынақ сценарийі. Мұндай интерфейстерді тиімді пайдаланудың көптеген тамаша мысалдары Java стандартты кітапханасында инкапсуляцияланған. Жинақтар, тізімдер, жиынтықтар – бұл интерфейстердің біркелкі ауыстырылуы мүмкін және келісім-шарттардың артықшылығы болған кезде ауыстырылуы мүмкін бірнеше іске асыру бар. Мысалы: 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. Жолдар
Жолдар Java тілінде де, басқа бағдарламалау тілдерінде де ең көп қолданылатын түрлердің бірі болып табылады. Java тілі біріктіру және салыстыру операцияларын қораптан тыс қолдап, көптеген әдеттегі жол манипуляцияларын жеңілдетеді. Сонымен қатар, стандартты кітапханада жол операцияларын тиімді ететін көптеген сыныптар бар. Бұл біз осы бөлімде талқылайтын нәрсе. Java тілінде жолдар UTF-16 codeтауында ұсынылған өзгермейтін нысандар болып табылады. Жолдарды біріктірген сайын (немесе бастапқы жолды өзгертетін кез келген әрекетті орындаған кезде), String класының жаңа данасы жасалады . Осыған байланысты біріктіру операциясы өте тиімсіз болуы мүмкін, бұл String класының көптеген аралық даналарының жасалуын тудырады (жалпы қоқыс жасау). Бірақ Java стандартты кітапханасында екі өте пайдалы сынып бар, олардың мақсаты жолды манипуляциялауды ыңғайлы ету болып табылады. Бұл StringBuilder және StringBuffer (олардың арасындағы жалғыз айырмашылық StringBuffer ағыны қауіпсіз, ал StringBuilder керісінше). Қолданылатын осы сыныптардың бірінің бірнеше мысалын қарастырайық: 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(), "]" ); пайдалану жолдарды өңдеудің ұсынылатын жолы болып табылады, ол екі немесе үш жолды біріктірудің қарапайым сценарийінде шамадан тыс көрінуі мүмкін, осылайша қалыпты қосу операторы ( («+»), мысалы: Біріктіруді жеңілдетудің ең жақсы баламасы статикалық String.format көмекші әдісін қамтамасыз ету үшін жол пішімдеуімен қатар Java стандартты кітапханасын пайдалану болып табылады . Бұл пішім спецификаторларының бай жинағын қолдайды, соның ішінде сандар, таңбалар, күн/уақыт және т.б. (Толық мәліметтер үшін анықтамалық құжаттаманы қараңыз) String.format әдісі әртүрлі деректер түрлерінен жолдарды жасау үшін таза және жеңіл тәсілді қамтамасыз етеді. Қазіргі Java IDE-лері String.format әдісіне берілген аргументтерден пішім спецификациясын талдай алатынын және сәйкессіздіктер анықталған жағдайда әзірлеушілерді ескертетінін атап өткен жөн. 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. Атау шарты
Java - әзірлеушілерді кез келген атау конвенциясын қатаң сақтауға мәжбүрлемейтін тіл, бірақ қауымдастық Java codeын стандартты кітапханада да, кез келген басқа Java жобаларында да үйлесімді етіп көрсететін қарапайым ережелер жинағын әзірледі:
  • бума атаулары кіші әріппен жазылады: org.junit, com.fasterxml.jackson, javax.json
  • сыныптардың атаулары, тізімдер, интерфейстер, annotationлар бас әріппен жазылады: StringBuilder, Runnable, @Override
  • өрістердің немесе әдістердің атаулары ( статикалық финалдан басқа ) түйе белгісінде көрсетіледі: isEmpty, format, addAll
  • статикалық соңғы өріс немесе санаудың тұрақты атаулары астын сызумен («_») бөлінген бас әріппен жазылады: LOG, MIN_RADIX, INSTANCE.
  • жергілікті айнымалылар немесе әдіс аргументтері түйе белгісінде теріледі: str, newLength, minimumCapacity
  • генериктерге арналған параметр түрінің атаулары бас әріппен бір әріппен беріледі: T, U, E
Осы қарапайым конвенцияларды орындай отырып, сіз жазған code қысқа және стилі бойынша басқа кітапханадан немесе құрылымнан ерекшеленбейтін болып көрінеді және оны бір адам жасағандай сезінеді (конвенциялар шынымен жұмыс істейтін сирек жағдайлардың бірі).
9. Стандартты кітапханалар
Қандай Java жобасымен жұмыс істеп жатсаңыз да, Java стандартты кітапханалары сіздің ең жақсы достарыңыз болып табылады. Иә, олардың кейбір өрескел жиектері мен оғаш дизайн шешімдері бар екендігімен келіспеу қиын, дегенмен 99% уақытында бұл сарапшылар жазған жоғары сапалы code. Зерттеуге тұрарлық. Әрбір Java шығарылымы бұрыннан бар кітапханаларға көптеген жаңа мүмкіндіктер береді (ескі мүмкіндіктерге қатысты кейбір ықтимал мәселелермен), сонымен қатар көптеген жаңа кітапханаларды қосады. Java 5 java.util.concurrent бумасының бөлігі ретінде жаңа параллельдік кітапхананы әкелді . Java 6 сценарийлерді ( javax.script бумасы) және Java компиляторының API интерфейсін ( javax.tools бумасының бөлігі ретінде) қолдауды (кем танымал) қамтамасыз етті . Java 7 java.util.concurrent жүйесіне көптеген жақсартулар әкелді , java.nio.file бумасында жаңа енгізу/шығару кітапханасын және java.lang.invoke динамикалық тілдерін қолдауды ұсынды . Соңында Java 8 көптен күткен күнді/уақытты java.time пакетіне қосты . Java платформасы ретінде дамып келеді және оның жоғарыда аталған өзгерістермен бірге ілгерілеуі өте маңызды. Жобаңызға үшінші тарап кітапханасын немесе фреймворкті қосуды қарастырған сайын, талап етілетін функционалдылықтың стандартты Java кітапханаларында жоқ екеніне көз жеткізіңіз (әрине, алгоритмдердің көптеген мамандандырылған және жоғары өнімді іске асырулары бар. стандартты кітапханалардағы алгоритмдер, бірақ көп жағдайда олар шынымен қажет емес).
10. Өзгермейтіндік
Нұсқаулықтағы және осы бөліктегі өзгермейтіндік еске салу ретінде қалады: оны байыппен қабылдаңыз. Егер сіз құрастырған класс немесе сіз енгізген әдіс өзгермейтіндік кепілдігін бере алатын болса, оны бір уақытта өзгертуден қорықпай барлық жерде қолдануға болады. Бұл әзірлеуші ​​ретінде сіздің өміріңізді (және сіздің команда мүшелерінің өмірін) жеңілдетеді.
11. Тестілеу
Тестке негізделген әзірлеу тәжірибесі (TDD) Java қауымдастығында өте танымал, бұл code сапасы үшін жолақты жоғарылатады. TDD ұсынатын барлық артықшылықтарға қарамастан, Java стандартты кітапханасы бүгінгі күні ешқандай сынақ шеңберін немесе қолдау құралдарын қамтымайтынын көру өкінішті. Дегенмен, тестілеу қазіргі заманғы Java әзірлеуінің қажетті бөлігіне айналды және бұл бөлімде біз JUnit негізін қолданатын бірнеше негізгі әдістерді қарастырамыз . JUnit-те әрбір сынақ нысанның күтілетін күйі немесе әрекеті туралы мәлімдемелер жиынтығы болып табылады. Тамаша сынақтарды жазудың құпиясы - оларды қарапайым және қысқа етіп сақтау, бір уақытта бір нәрсені сынау. Жаттығу ретінде String.format жол бөліміндегі қажетті нәтижені қайтаратын функция екенін тексеру үшін тесттер жинағын жазайық. 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" ) ); } } Екі сынақ өте оқылатын көрінеді және олардың орындалуы дана болып табылады. Бүгінгі күні орташа Java жобасы жүздеген сынақ жағдайларын қамтиды, бұл әзірлеушіге регрессиялар немесе мүмкіндіктер бойынша әзірлеу процесі кезінде жылдам кері байланыс береді.
12. Келесі
Нұсқаулықтың бұл бөлігі Java тілінде бағдарламалау тәжірибесіне және осы бағдарламалау тіліне арналған нұсқаулықтарға қатысты бірқатар талқылауларды аяқтайды. Келесі жолы біз ерекше жағдайлар, олардың түрлері, оларды қалай және қашан пайдалану туралы Java әлемін зерттей отырып, тілдің мүмкіндіктеріне ораламыз.
13. Бастапқы codeты жүктеп алыңыз
Бұл Advanced Java курсынан жалпы даму принциптері туралы сабақ болды. Сабақтың бастапқы codeын мына жерден жүктеп алуға болады .
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION