JavaRush /Java Blogu /Random-AZ /Yeni başlayan java proqramçılarının səhvləri. 2-ci hissə
articles
Səviyyə

Yeni başlayan java proqramçılarının səhvləri. 2-ci hissə

Qrupda dərc edilmişdir
Yeni başlayan java proqramçılarının səhvləri. 1-ci hissə

9. Main() metodundan statik olmayan sinif metodlarının çağırılması

İstənilən Java proqramının giriş nöqtəsi statik metod olmalıdır main:
Yeni başlayan java proqramçılarının səhvləri.  Hissə 2 - 1
public static void main(String[] args) {
  ...
}
Bu metod statik olduğundan, ondan qeyri-statik sinif metodlarını çağıra bilməzsiniz. Şagirdlər çox vaxt bunu unudurlar və sinif nümunəsini yaratmadan metodları çağırmağa çalışırlar. Bu səhv adətən təlimin lap əvvəlində, tələbələr kiçik proqramlar yazarkən edilir. Səhv nümunə:
public class DivTest {
    boolean divisible(int x, int y) {
        return (x % y == 0);
    }

    public static void main(String[] args) {
        int v1 = 14;
        int v2 = 9;

        // на следующие строки компилятор выдаст ошибку
        if (divisible(v1, v2)) {
            System.out.println(v1 + " is a multiple of " + v2);
        } else {
            System.out.println(v2 + " does not divide " + v1);
        }
    }
}
Səhvləri düzəltməyin 2 yolu var: istədiyiniz metodu statik edin və ya sinifin nümunəsini yaradın. Düzgün metodu seçmək üçün özünüzdən soruşun ki, metod bir sahə və ya digər sinif metodlarından istifadə edir. Əgər belədirsə, onda siz sinfin nümunəsini yaratmalı və onun üzərində metodu çağırmalısınız, əks halda metodu statik hala gətirməlisiniz. Düzəliş edilmiş nümunə 1:
public class DivTest {
    int modulus;

    public DivTest(int m) {
      modulus = m;
    }

    boolean divisible(int x) {
        return (x % modulus == 0);
    }

    public static void main(String[] args) {
        int v1 = 14;
        int v2 = 9;

        DivTest tester = new DivTest(v2);

        if (tester.divisible(v1) {
            System.out.println(v1 + " is a multiple of " + v2);
        } else {
            System.out.println(v2 + " does not divide " + v1);
        }
    }
}
Düzəliş edilmiş nümunə 2:
public class DivTest {
    static boolean divisible(int x, int y) {
        return (x % y == 0);
    }

    public static void main(String[] args) {
        int v1 = 14;
        int v2 = 9;

        if (divisible(v1, v2)) {
            System.out.println(v1 + " is a multiple of " + v2);
        } else {
            System.out.println(v2 + " does not divide " + v1);
        }
    }
}

10. Metod parametrləri kimi String sinif obyektlərindən istifadə.

Java-da sinif java.lang.Stringsətir məlumatlarını saxlayır. Bununla belə, Java-da sətirlər
  1. daimiliyə malikdir (yəni dəyişdirilə bilməz),
  2. obyektlərdir.
Buna görə də, onlara sadəcə xarakter buferi kimi baxıla bilməz; onlar dəyişməz obyektlərdir. Bəzən tələbələr sətir obyektinin istinadla simvol massivi kimi ötürüləcəyini səhv gözləməklə sətirləri ötürürlər (C və ya C++ dillərində olduğu kimi). Kompilyator adətən bunu xəta hesab etmir. Səhv nümunə.
public static void main(String args[]) {
   String test1 = "Today is ";
   appendTodaysDate(test1);
   System.out.println(test1);
}

/* прим. редактора: закомментированный метод должен иметь модификатор
    static (здесь автором допущена ошибка №9)
public void appendTodaysDate(String line) {
    line = line + (new Date()).toString();
}
*/

public static void appendTodaysDate(String line) {
    line = line + (new Date()).toString();
}
Yuxarıdakı misalda tələbə metoddakı test1parametrə yeni dəyər təyin etməklə yerli dəyişənin dəyərini dəyişmək istəyir . Təbii ki, bu işləməyəcək. Məna dəyişəcək, amma məna eyni qalacaq. Bu xəta (1) java obyektlərinin həmişə istinadla ötürülməsi və (2) javadakı sətirlərin dəyişməz olması ilə bağlı anlaşılmazlıq səbəbindən baş verir. Siz başa düşməlisiniz ki, sətir obyektləri heç vaxt öz dəyərini dəyişmir və sətirlərdəki bütün əməliyyatlar yeni obyekt yaradır. Yuxarıdakı misaldakı xətanı düzəltmək üçün ya metoddan sətri qaytarmalı, ya da obyekti parametr kimi yerinə metoda ötürməlisiniz . Düzəliş edilmiş nümunə 1:lineappendTodaysDatelinetest1StringBufferString
public static void main(String args[]) {
   String test1 = "Today is ";
   test1 = appendTodaysDate(test1);
   System.out.println(test1);
}

public static String appendTodaysDate(String line) {
    return (line + (new Date()).toString());
}
Düzəliş edilmiş nümunə 2:
public static void main(String args[]) {
   StringBuffer test1 = new StringBuffer("Today is ");
   appendTodaysDate(test1);
   System.out.println(test1.toString());
}

public static void appendTodaysDate(StringBuffer line) {
    line.append((new Date()).toString());
}

təqribən. tərcümə
Əslində, səhvin nə olduğunu başa düşmək o qədər də asan deyil. Obyektlər istinad yolu ilə ötürüldüyü üçün, o, lineilə eyni yerə istinad edir test1. Bu o deməkdir ki, yenisini yaratmaqla linebiz yenisini yaradırıq.Yanlış test1nümunədə hər şey köçürmə Stringistinadla deyil, dəyərlə olduğu kimi görünür.

11. Konstruktorun metod kimi elan edilməsi

Java-da obyekt konstruktorları xarici görünüşcə adi metodlara bənzəyir. Yeganə fərq odur ki, konstruktor qaytarma növü təyin etmir və adı sinif adı ilə eynidir. Təəssüf ki, Java metod adının sinif adı ilə eyni olmasına imkan verir. Aşağıdakı nümunədə tələbə Vector listsinfi yaratarkən sinif sahəsini işə salmaq istəyir. Bu baş verməyəcək, çünki metod 'IntList'konstruktor deyil. Səhv nümunə.
public class IntList {
    Vector list;

    // Выглядит How конструктор, но на самом деле это метод
    public void IntList() {
        list = new Vector();
    }

    public append(int n) {
        list.addElement(new Integer(n));
    }
}
NullPointerExceptionSahəyə ilk dəfə daxil olduqda kod bir istisna atacaq list. Səhv düzəltmək asandır: sadəcə metodun başlığından qaytarılan dəyəri silmək lazımdır. Düzəliş edilmiş nümunə:
public class IntList {
    Vector list;

    // Это конструктор
    public IntList() {
        list = new Vector();
    }

    public append(int n) {
        list.addElement(new Integer(n));
    }
}

12. Obyekti tələb olunan tipə köçürməyi unutmusunuz

Bütün digər obyekt yönümlü dillər kimi, Java-da siz obyektə onun superklassı kimi müraciət edə bilərsiniz. Bu adlanır 'upcasting', Java-da avtomatik olaraq edilir. Bununla belə, əgər dəyişən, sinif sahəsi və ya metodun qaytarılması dəyəri superklass kimi elan edilərsə, alt sinifin sahələri və metodları görünməz olacaqdır. Bir alt sinif kimi bir supersinifa istinad 'downcasting', onu özünüz qeydiyyatdan keçirməlisiniz (yəni obyekti istədiyiniz alt sinifə gətirin). Şagirdlər çox vaxt obyekti alt siniflərə ayırmağı unudurlar. Bu, ən çox Obyekt massivlərindən paketdən kolleksiyalardan istifadə edərkən baş verir ( Kolleksiya Çərçivəsijava.util deməkdir ). Aşağıdakı nümunə obyekti massivə qoyur və sonra onu başqa sətirlə müqayisə etmək üçün onu massivdən çıxarır. Kompilyator xətanı aşkar edəcək və cast növü açıq şəkildə göstərilməyənə qədər kodu tərtib etməyəcək. Səhv nümunə.String
Object arr[] = new Object[10];
arr[0] = "m";
arr[1] = new Character('m');

String arg = args[0];
if (arr[0].compareTo(arg) < 0) {
    System.out.println(arg + " comes before " + arr[0]);
}
Tipli tökmənin mənası bəziləri üçün çətindir. Dinamik üsullar xüsusilə tez-tez çətinliklər yaradır. Yuxarıdakı misalda metod equalsəvəzinə istifadə edilsəydi compareTo, kompilyator xəta verməzdi və equalssinifin metodu çağırılacağı üçün kod düzgün işləyəcəkdi String. Dinamik əlaqənin fərqli olduğunu başa düşməlisiniz downcasting. Düzəliş edilmiş nümunə:
Object arr[] = new Object[10];
arr[0] = "m";
arr[1] = new Character('m');

String arg = args[0];
if ( ((String) arr[0]).compareTo(arg) < 0) {
    System.out.println(arg + " comes before " + arr[0]);
}

13. İnterfeyslərdən istifadə.

Bir çox tələbələr üçün siniflər və interfeyslər arasındakı fərq tam aydın deyil. Buna görə də, bəzi tələbələr apps əvəzinə extensions açar sözündən istifadə etməklə Observervə ya kimi interfeysləri həyata keçirməyə çalışırlar . Səhvi düzəltmək üçün açar sözü düzgün olana düzəltmək kifayətdir. Səhv nümunə:Runnable
public class SharkSim extends Runnable {
    float length;
    ...
}
Düzəliş edilmiş nümunə:
public class SharkSim implements Runnable {
    float length;
    ...
}
Əlaqədar xəta: Genişləndiricitətbiq bloklarının səhv sırası . Java spesifikasiyasına görə, sinif genişləndirilməsi bəyannamələri interfeys tətbiqi bəyannamələrindən əvvəl gəlməlidir. Həmçinin, interfeyslər üçün implements açar sözünün yalnız bir dəfə yazılması lazımdır; çoxlu interfeyslər vergüllə ayrılır. Daha bir neçə səhv nümunə:
// Неправильный порядок
public class SharkSim implements Swimmer extends Animal {
    float length;
    ...
}

// ключевое слово implements встречается несколько раз
public class DiverSim implements Swimmer implements Runnable {
    int airLeft;
    ...
}
Düzəliş edilmiş nümunələr:
// Правильный порядок
public class SharkSim extends Animal implements Swimmer {
    float length;
    ...
}

// Несколько интерфейсов разделяются запятыми
public class DiverSim implements Swimmer, Runnable {
    int airLeft;
    ...
}

14. Superclass metodunun qaytarılması dəyərindən istifadə etməyi unutmusunuz

Java sizə açar söz açar sözündən istifadə edərək alt sinifdən oxşar superclass metodunu çağırmağa imkan verir. Bəzən tələbələr superclass metodlarını çağırmalı olurlar, lakin çox vaxt qaytarılan dəyərdən istifadə etməyi unudurlar. Bu, xüsusilə metodları və onların qaytarılma dəyərlərini hələ başa düşməyən tələbələr arasında baş verir. Aşağıdakı misalda tələbə toString()superklass metodunun nəticəsini alt sinif metodunun nəticəsinə daxil etmək istəyir toString(). Bununla belə, superclass metodunun qaytarılması dəyərindən istifadə etmir. Səhv nümunə:
public class GraphicalRectangle extends Rectangle {
      Color fillColor;
      boolean beveled;
      ...
      public String toString() {
          super();
          return("color=" + fillColor + ", beveled=" + beveled);
      }
}
Xətanı düzəltmək üçün adətən yerli dəyişənə qaytarılan dəyəri təyin etmək kifayətdir və sonra alt sinif metodunun nəticəsini hesablayarkən həmin dəyişəndən istifadə etmək kifayətdir. Düzəliş edilmiş nümunə:
public class GraphicalRectangle extends Rectangle {
      Color fillColor;
      boolean beveled;
      ...
      public String toString() {
          String rectStr = super();
          return(rectStr + " - " +
         "color=" + fillColor + ", beveled=" + beveled);
      }
}

15. AWT komponentlərini əlavə etməyi unutmusunuz

AWT sadə GUI dizayn modelindən istifadə edir: hər bir interfeys komponenti əvvəlcə öz konstruktoru ilə yaradılmalı, sonra isə add()ana komponent metodundan istifadə edərək proqram pəncərəsinə yerləşdirilməlidir. Beləliklə, AWT-də interfeys iyerarxik bir quruluş alır. Tələbələr bəzən bu 2 addımı unudurlar. Onlar komponent yaradırlar, lakin onu böyütmə pəncərəsinə yerləşdirməyi unudurlar. Bu kompilyasiya mərhələsində səhvlərə səbəb olmayacaq; komponent sadəcə proqram pəncərəsində görünməyəcək. Səhv nümunə.
public class TestFrame extends Frame implements ActionListener {
    public Button exit;

    public TestFrame() {
        super("Test Frame");
        exit = new Button("Quit");
    }
}
Bu səhvi düzəltmək üçün sadəcə komponentləri valideynlərinə əlavə etməlisiniz. Aşağıdakı nümunə bunun necə ediləcəyini göstərir. Qeyd etmək lazımdır ki, çox vaxt proqram pəncərəsinə komponent əlavə etməyi unudan tələbə həmin komponentə hadisə dinləyiciləri təyin etməyi də unudur. Düzəliş edilmiş nümunə:
public class TestFrame extends Frame implements ActionListener {
    public Button exit;

    public TestFrame() {
        super("Test Frame");

        exit = new Button("Quit");

        Panel controlPanel = new Panel();
        controlPanel.add(exit);

        add("Center", controlPanel);

        exit.addActionListener(this);
    }

    public void actionPerformed(ActionEvent e) {
        System.exit(0);
    }
}

17. Yayımı başlatmağı unutmuşam

Java-da multithreading istifadə edərək həyata keçirilir java.lang.Thread. Bir ipin həyat dövrü 4 mərhələdən ibarətdir: işə salındı, başladı, bloklandı və dayandırıldı. Yeni yaradılmış başlıq başlanğıc vəziyyətindədir. Onu işlək vəziyyətə gətirmək üçün onu çağırmalısınız start(). Bəzən tələbələr mövzular yaradır, lakin onları başlatmağı unudurlar. Adətən səhv, tələbənin paralel proqramlaşdırma və çox iş parçacığı haqqında kifayət qədər biliyə malik olmadığı zaman baş verir. (təxminən tərcümə: Mən əlaqəni görmürəm) Xətanı düzəltmək üçün sadəcə mövzunu başlamaq lazımdır. Aşağıdakı misalda tələbə interfeysdən istifadə edərək şəkilin animasiyasını yaratmaq istəyir Runnable, lakin o, mövzunu açmağı unutmuşdur. Səhv nümunə
public class AnimCanvas extends Canvas implements Runnable {
        protected Thread myThread;
        public AnimCanvas() {
                myThread = new Thread(this);
        }

        // метод run() не будет вызван,
        // потому что поток не запущен.
        public void run() {
                for(int n = 0; n < 10000; n++) {
                   try {
                     Thread.sleep(100);
                   } catch (InterruptedException e) { }

                   animateStep(n);
                }
        }
        ...
}
Düzəliş edilmiş nümunə:
public class AnimCanvas extends Canvas implements Runnable {
        static final int LIMIT = 10000;
        protected Thread myThread;

        public AnimCanvas() {
                myThread = new Thread(this);
                myThread.start();
        }

        public void run() {
                for(int n = 0; n < LIMIT; n++) {
                        try {
                          Thread.sleep(100);
                        } catch (InterruptedException e) { }

                        animateStep(n);
                }
        }
        ...
}
Bir ipin həyat dövrü və interfeysi həyata keçirən iplər və siniflər arasındakı əlaqə RunnableJava proqramlaşdırmasının çox vacib hissəsidir və buna diqqət yetirmək faydalı olardı.

18. java.io.DataInputStream sinfinin qadağan olunmuş readLine() metodundan istifadə

Java 1.0 versiyasında mətn sətirini oxumaq üçün readLine()sinif metodundan istifadə etməli idiniz java.io.DataInputStream. Java versiyası 1.1 mətn üçün I/O əməliyyatlarını təmin etmək üçün I/O siniflərinin bütün dəstini əlavə etdi: ReaderWriter. Beləliklə, 1.1 versiyasından mətn sətirini oxumaq üçün readLine()sinif metodundan istifadə etməlisiniz java.io.BufferedReader. Şagirdlər bu dəyişikliyin fərqində olmaya bilər, xüsusən də onlara köhnə kitablardan öyrədilibsə. (təxminən. Tərcümə: əslində artıq aktual deyil. Çətin ki, indi kimsə 10 yaşında olan kitabları öyrənsin). Köhnə üsul readLine()JDK-da qalır, lakin qeyri-qanuni elan edilir, bu da tez-tez tələbələri çaşdırır. Anlamalısınız ki, readLine()sinif metodundan istifadə etmək java.io.DataInputStreamsəhv deyil, sadəcə köhnəlmişdir. Siz sinifdən istifadə etməlisiniz BufferedReader. Səhv nümunə:
public class LineReader {
    private DataInputStream dis;

    public LineReader(InputStream is) {
        dis = new DataInputStream(is);
    }

    public String getLine() {
        String ret = null;

        try {
          ret = dis.readLine();  // Неправильно! Запрещено.
        } catch (IOException ie) { }

        return ret;
    }
}
Düzəliş edilmiş nümunə:
public class LineReader {
    private BufferedReader br;

    public LineReader(InputStream is) {
        br = new BufferedReader(new InputStreamReader(is));
    }

    public String getLine() {
        String ret = null;

        try {
          ret = br.readLine();
        } catch (IOException ie) { }

        return ret;
    }
}
1.0-dan sonrakı versiyalarda başqa qadağan olunmuş üsullar da var, lakin bu ən çox yayılmışdır.

19. Float kimi ikiqat istifadə

Əksər digər dillər kimi, Java da üzən nöqtəli ədədlər (kəsir ədədlər) üzərində əməliyyatları dəstəkləyir. Java-nın üzən nöqtəli nömrələr üçün iki primitiv növü var: doubleIEEE 64-bit dəqiqliyi və floatIEEE 32-bit dəqiqliyi. Çətinlik ondadır ki, 1.75, 12.9e17 və ya -0.00003 kimi onluq ədədlərdən istifadə edərkən tərtibçi onları tipə təyin edir double. Java dəqiqlik itkisinin baş verə biləcəyi əməliyyatlarda tip tökmələri yerinə yetirmir. Bu tip tökmə proqramçı tərəfindən edilməlidir. Məsələn, Java sizə aşağıdakı nümunədə göstərildiyi kimi tip ötürülməsi olmayan tip intdəyişəninə tip dəyəri təyin etməyə icazə verməyəcək.byte
byte byteValue1 = 17; /* неправильно! */
byte byteValue2 = (byte)19; /* правильно */
Kəsr ədədlər növü ilə təmsil olunduğundan doubledoubletip dəyişəninə təyinat floatdəqiqliyin itirilməsinə səbəb ola biləcəyi üçün tərtibçi kəsr ədədləri kimi istifadə etmək cəhdindən şikayət edəcək float. Beləliklə, aşağıdakı tapşırıqlardan istifadə sinfin tərtib edilməsinə mane olacaq.
float realValue1 = -1.7;          /* неправильно! */
float realValue2 = (float)(-1.9); /* правильно */
Bu tapşırıq C və ya C++ dillərində işləyəcək, lakin Java-da daha sərtdir. Bu səhvdən qurtulmağın 3 yolu var. doubleəvəzinə type istifadə edə bilərsiniz float. Bu, ən sadə həll yoludur. Əslində, 64 bit əvəzinə 32 bitlik hesabdan istifadə etməyin mənası yoxdur; sürət fərqi hələ də JVM tərəfindən yeyilir (bundan əlavə, müasir prosessorlarda bütün fraksiya ədədləri 80 bitlik prosessorun formatına çevrilir. hər hansı bir əməliyyatdan əvvəl qeydiyyatdan keçin). Onlardan istifadənin yeganə üstünlüyü floatondan ibarətdir ki, onlar daha az yaddaş tuturlar ki, bu da çoxlu sayda fraksiya dəyişənləri ilə işləyərkən faydalıdır. Siz tərtibçiyə nömrənin necə saxlanacağını söyləmək üçün nömrə növü dəyişdiricisindən istifadə edə bilərsiniz. Növ üçün dəyişdirici float - 'f'. Beləliklə, kompilyator 1.75 tipini double, və üçün təyin edəcək 1.75f - float. Misal üçün:
float realValue1 = 1.7;    /* неправильно! */
float realValue2 = 1.9f;   /* правильно */
Siz açıq tipli yayımdan istifadə edə bilərsiniz. doubleBu, ən az zərif üsuldur, lakin bir növ dəyişənini bir növə çevirərkən faydalıdır float. Misal:
float realValue1 = 1.7f;
double realValue2 = 1.9;
realValue1 = (float)realValue2;
Üzən nöqtə nömrələri haqqında daha çox oxuya bilərsiniz burada və burada.

-- tərcüməçinin şərhi --
Bu qədər.
10-cu misalda 9-cu səhv həqiqətən edilib.Mən bunu dərhal fərq etdim, lakin qeyd yazmağı unutdum. lakin orijinal mənbə ilə heç bir uyğunsuzluq olmasın deyə, onu düzəltməyib.

Müəllif: A.Grasoff™ Mənbəyə keçid: Yeni başlayan java proqramçılarının səhvləri
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION