прегледано: |
210950 |
вкупно гласови: |
1 |
средна оценка: |
4.0 |
коментари: |
2 |
испрати до пријател
испечати
|
Дури и да ја знаете Java-та како прстите на вашата рака, или сте почетник во програмирањето, ќе правите грешки. Природно е, човечки е, и погодете што? Најверојатно ќе ги правите истите грешки што ги прават другите, повторно и повторно. Ова е мојата листа на десет најпознати грешки што сите ги правиме, како да ги пронајдеме, и како да ги исправиме.
10. Пристапување на нестатички променливи од статички методи (како main)
Многу програмери, посебно оние нови во Java, имаат проблеми со пристапување на променливи од нивниот main метод. Методот main е маркиран како static - значи дека не треба да креираме инстанца од класата за да го повикаме main методот. На пример, Java виртуелната машина (JVM) може да ја повика апликацијата вака:
MyApplication.main ( command_line_args );
Ова значи дека не постои инстанца од MyApplication - нема променливи за пристап. На пример, следново ќе генерира компајлерска грешка:
public class StaticnoDemo {
public String moja_promenliva = "nekoj podatok";
public static void main (String args[]) {
// Pristap do nestaticka promenliva od staticki metod
System.out.println ("Ova generira kompajlerska greska" + moja_promenliva );
}
}
Ако сакате да пристапите на класните променливи од нестатички метод (како main), мора да креирате инстанца од класата. Еве пример како правилно да напишете код за пристап до нестатички класни променливи:
public class NeStaticnoDemo {
public String moja_promenliva = "nekoj podatok";
public static void main (String args[]) {
NeStaticnoDemo demo = new NeStaticnoDemo();
// Pristapi klasna promenliva
System.out.println ("Ova nema da generira greska: " + demo.moja_promenliva );
}
}
9. Грешење на името на методот при преклопување (override)
Преклопувањето им дозволува на програмерите да ја заменат имплементацијата на методот со нов код. Многу ОО програмери често го користат. Ако користите AWT 1.1 модел за справување со настани, често ќе преклопите имплементации на listeners за да дадете своја имплементација. Еден лесен начин да паднете во стапица е погрешно да го именувате методот. Ако го сторите тоа, веќе не преклопувате метод - креирате сосема нов метод, но со исти тип на параметри и повратен тип.
public class MyWindowListener extends WindowAdapter {
// Ova treba da bide WindowClosed
public void WindowClose(WindowEvent e) {
// Izleguva od programa koga korisnikot kje go iskluci prozorot
System.exit(0);
}
}
Компајлерите нема да реагираат на оваа грешка и затоа овој проблем е тежок да се пронајде. Симптомите на оваа грешка се изразуваат на тој начин што методот нема да биде повикан. Најдобар начин за да видите дали еден метод се повикува или не е да ставите println, да запишете порака во log фајл, или да користите trace debugger и да извршувате линија по линија. Ако вашиот метод не е повикан, значи дека сте му го погрешиле името.
8. Споредба и доделување ( = наместо == )
Оваа грешка лесно се прави. Ако сте користеле други програмски јазици претходно, како Pascal, ќе видите колку лош избор било ова на програмерите на јазикот. Во Pascal, на пример, користиме оператор := за доделување, а = за споредба. Ова личи како недостаток на C/C++, од кои Java-та влече корени.
За среќа, дури и да не го забележите ова при гледање на кодот на екран, компајлерот ќе го забележи. Најчесто, ќе пројави порака за грешка како "Can't convert xxx to boolean", каде xxx е тип во Java кој го доделувате наместо да го споредувате.
7. Споредба на два објекта ( == наместо .equals )
Кога го користиме операторот ==, всушност споредуваме референци на два објекта, за да провериме дали покажуваат на истиот објект. Не можеме да споредуваме два string-а за еднаквост користејќи го операторот ==. Во овој случај, го користиме методот equals, кој е метод наследен од страна на сите класи од java.lang.Object.
Еве правилен начин да споредувате два string-a.
String abc = "abc"; String def = "def".
// Los nacin
if ( (abc + def) == "abcdef" ) {
......
}
// Dobar nacin
if ( (abc + def).equals("abcdef") ) {
.....
}
6. Забуна при праќање на вредност и праќање преку референца
Ова може да биде фрустрирачки проблем за дијагностицирање, бидејќи кога гледате во кодот, можете да бидете сигурни дека праќате по референца, но отпосле пронаоѓате дека праќате вредност. Java ги користи и двата начина, и треба да ги разберете и двата.
Кога праќате примитивен тип на податок (како char, int, float, или double) на метод, тогаш праќате вредност. Тоа значи дека се прави копија на податокот и се праќа во методот. Ако методот ја модифицира вредноста, ќе ја модифицира само копијата. Штом заврши функцијата и се врати контролата кон повикувачката функција, "правата" променлива е недопрена. Ако целта е да модифицирате примитивен тип на податок, тогаш вратете го како повратен тип од функција, или ставете го во објект.
Кога праќате Java објект (како array, vector или string) на метод, тогаш праќате референца. Да, String е всушност објект, а не примитивен тип на податок. Тоа значи дека кога праќате објект во метод, праќате референца, а не дупликат. Секоја промена на класните променливи на објектот ќе бидат перманенти - што може да биде и добро и лошо, зависно од намерата.
Инаку, String не содржи методи за промена на содржината, па може да се искористи и за праќање по вредност.
5. Празен блок при исклучок (exception)
Најлесно е да се остави празен блок при случај на исклучок и да се игнорираат грешките. Но, ако навлезете во проблеми и немате пораки за грешки, станува невозможно да ги најдете причините за грешките. Дури и наједноставниот код во блокот на исклучокот може да даде придонес. На пример, ставете try { .. } catch Exception околу вашиот код за да фатите било каков тип на исклучок, и испечатете порака. Не мора да пишувате посебен handler за секој исклучок (иако ова е добра програмерска практика). Но, не оставајте празен блок, бидејќи нема да знаете што се случува. На пример:
public static void main(String args[]) {
try {
// Vasiot kod doagja tuka
} catch (Exception e) {
System.out.println ("Greska - " + e );
}
}
4. Заборавање дека Јава е нулто индексирана
Доколку имаш познавања од C/C++ оваа точка не ти е проблем за разлика од оние кои користеле други јазици. Во Јава низите се нулто индексирани, односно индексот (позицијата) на првиот елемент во низата е 0 (нула). Збунет? Ајде едно примерче набрзина:
// Kreiranje na niza so tri stringa
String[] strNiza = new String[3];
// Indeksot na prviot element vsusnost e 0 (nula)
strNiza[0] = "Prv string";
// Indeksot na vtoriot element e 1 (eden)
strNiza[1] = "Vtor string";
// Indeksot na tretiot element e 2 (dva)
strNiza[2] = "Tret string";
Во овој пример имавме низа од 3 стринга, но за да пристапиме до елемтите во низата ние целовреме ќе треба да одземаме 1. На пример, доколку би пробале да пристапиме до strNiza[3] ние всушност пробуваме да пристапиме до 4-тиот елемент. Ова ќе фрли ArrayOutOfBoundsException, најочигледен знак дека сме го заборавиле правилото за нулто индексирање.
Друго место каде што нултото индексирање ќе ти донесе невоља се стринговите. На пример, доколку сакаш да „собереш“ карактер кој е на некоја позиција во стринг. Користејќи ја методата String.charAt(int) можеш да го изведеш тоа, но внимавај, во Јава класата String е исто така нулто индексирана. Тоа значи дека првиот карактер во низата од карактери (стрингот) е на позиција 0 (нула), вториот е на позиција 1 итн. Ова понекогаш стварно знае да биде фрустрирачки кога ќе се подрзаборави на ова, а посебно тоа ако се случи во апликација која целовремено работи со процесирање на стрингови. Доколку се погреши индексот на карактерите во run-time ќе добиеш грешка слична на онаа ArrayOutOfBoundsException, но овде прилагодена на пригодата, односно StringIndexOutOfBoundsException или како на пример:
public class StringDemo
{
public static void main (String args[]) {
String abc = "abc";
System.out.println ("Karakter na pozicija 0 : " + abc.charAt(0) );
System.out.println ("Karakter na pozicija 1 : " + abc.charAt(1) );
System.out.println ("Karakter na pozicija 2 : " + abc.charAt(2) );
// Ova ke isfrli Exception od tipot: StringIndexOutOfBoundsException
System.out.println ("Karakter na pozicija 3 : " + abc.charAt(3) );
}
}
Но запамети дека нултото индексирање не завршува на низи (Array) и на стрингови (String). Други делови од Јава-та се индексирани исто така, но не секогаш конзистентно. На пример класите java.util.Date и java.util.Calendar месеците ги започнуваат со 0 (нула), но деновите ги започнуваат со 1. Овој проблем би го демонстрирале во следниов пример:
import java.util.Date;
import java.util.Calendar;
public class NultoIndeksiranDatum
{
public static void main (String args[]) {
// Zemi go denesniot datum koristejki Date
Date denes = new Date();
// Ispecati ja povratnata vrednost od getMonth()
System.out.println ("Date.getMonth() vraka : " +
denes.getMonth());
// Zemi go denesniot datum koristejki Calendar
Calendar sega = Calendar.getInstance();
// Ispecati ja povratnata vrednost od get ( Calendar.MONTH )
System.out.println ("Calendar.get (month) vraka : " +
sega.get ( Calendar.MONTH ));
}
}
3. Заштита од конкурентен пристап до споделени променливи од страна на нишките (Threads)
Кога пишиваат програми со повеќе нишки (multi threading), многу програмери често ја фаќаат пократката патека и ги оставаат своите апликации ранливи на конфликти помеѓу нишки. Кога две или повеќе нишки конкуретно пристапуваат до некој податок тогаш постои можност (а законите на Марфи секогаш важат) дека две нишки ќе притапат или ќе го модифицираат истиот податок во исто време. Немој да мислиш дека таков проблем нема да се јави кај процесорите со една нишка (single threaded). Додека пристапува до некој податок (извршувајќи читање на податокот) твојата нишка може да биде суспендирана (ставена во мирување), а друга да почне со работа (на нејзе и дошло време на извршување, нејзините 5 милисекунди). Тогаш втората нишка ги запишува податоците, кои ќе бидат пребришани кога првата нишка ќе ги направи своите промени.
Такви проблеми не се лимитирани на апликациите со повеќе нишки или на аплети. Доколку пишувап Јава API-ја или JavaBeans, тогаш твојот код може да не биде thread-safe. Но дури и никогаш да не напишеш апликација која ќе користи нишки (thread-ови) луѓето кои ќе го користат твојот код најверојатно ќе користат. Затоа за да бидат раат тие, ако не ти, секогаш треба да се трудиш и да спречиш конкурентен пристап до податоци кои се делат.
Како ова да се спречи? Еден начин е опишан во написот Единствен Јава објект (singleton).
2. Грешки со големи/мали букви
Ова е една од најчестите грешки кои се (и ќе се) прават. Толку е едноставно да се направи, а некогаш може да се загледаш во самата грешка и да не ја приметиш разликата во големите/мали букви.
Иако нема конечно решение за таквите грешки лесно може да се привикнеш да правиш што помалце такви грешки. Едноставно следи барем неколку принципи од Јава конвенцијата за изворен код, односно запомни дека:
- сите методи и променливи во Јава започнуваат со мала буква
- сите методи и променливи користат голема буква онаму каде што треба да започне нов збор. На пример: getDoubleValue()
1. Покажувачите кон Null (Null pointers)!
Покажувачите кон Null вредност се најчеста грешка која Јава програмерите ја прават. Компајлерот неможе да ја најде оваа грешка за тебе, таа ќе се покаже сасмо во време на извршување на програмот, а доколку ти не ја откриеш, корисниците на програмот сигурно ќе ја откријат.
Кога ќе се проба да се пристапи до некој објект, а референцата до тој објект е „null“ тогаш Јава-та фрла NullPointerException. Причината за покажувачите кон null можат да бидат најразлични, но најчесто е заборавена иницијализација на некој објект или не е проверен резултатот од некоја повикана метода.
Многу функции враќаат null вредност за да индицираат некоја грешка, но доколку не ја провериш повратната вредност од функцијата никогаш нема да знаеш што се случува. А поради тоа што грешката се јавува само при одредени околности, нормалното тестирање нема да вроди со плод, а тоа ќе доведе да твоите корисници (корисниците на твојот програм) ја бараат грешката за тебе.
Друг случај е на пример каде што иницијализацијата е пропратена со малце невнимание или каде што таа е условна. На пример разгледај го следниов код и опробај се да го најдеш проблемот:
public static void main(String args[]) {
// Prima maximum 3 parametri
String[] lista = new String[3];
int index = 0;
while ( (index < args.length) "
}
// Proveti gi site parametri
for (int i = 0; i < lista.length; i++) {
if (lista[i].equals "-help") {
// .........
} else
if (lista[i].equals "-cp") {
// .........
}
// else .....
}
}
Доколку неуспеа да најдеш можен проблем, прочитај го истиот на следната страна.
|