Apa itu tumpukan jejak, dan bagaimana saya bisa menggunakannya untuk men-debug kesalahan aplikasi saya?


643

Terkadang ketika saya menjalankan aplikasi saya itu memberi saya kesalahan yang terlihat seperti:

Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16)
        at com.example.myproject.Author.getBookTitles(Author.java:25)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

Orang-orang menyebut ini sebagai "tumpukan jejak". Apa itu tumpukan jejak? Apa yang bisa saya katakan tentang kesalahan yang terjadi di program saya?


Tentang pertanyaan ini - cukup sering saya melihat pertanyaan datang di mana seorang programmer pemula "mendapatkan kesalahan", dan mereka hanya menempelkan jejak tumpukan mereka dan beberapa blok kode acak tanpa memahami apa jejak tumpukan itu atau bagaimana mereka dapat menggunakannya. Pertanyaan ini dimaksudkan sebagai referensi untuk pemrogram pemula yang mungkin perlu bantuan memahami nilai jejak tumpukan.


25
Juga, jika baris stacktrace tidak mengandung nama file dan nomor baris, kelas untuk baris itu tidak dikompilasi dengan informasi debug.
Thorbjørn Ravn Andersen

Jawaban:


590

Dalam istilah sederhana, jejak tumpukan adalah daftar metode panggilan bahwa aplikasi berada di tengah ketika Pengecualian dilemparkan.

Contoh sederhana

Dengan contoh yang diberikan dalam pertanyaan, kita dapat menentukan dengan tepat di mana pengecualian dilemparkan ke dalam aplikasi. Mari kita lihat jejak stack:

Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16)
        at com.example.myproject.Author.getBookTitles(Author.java:25)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

Ini adalah jejak tumpukan yang sangat sederhana. Jika kita mulai dari awal daftar "at ...", kita dapat mengetahui di mana kesalahan kita terjadi. Yang kami cari adalah pemanggilan metode teratas yang merupakan bagian dari aplikasi kami. Dalam hal ini, ini:

at com.example.myproject.Book.getTitle(Book.java:16)

Untuk men-debug ini, kita dapat membuka Book.javadan melihat baris 16, yaitu:

15   public String getTitle() {
16      System.out.println(title.toString());
17      return title;
18   }

Ini akan menunjukkan bahwa sesuatu (mungkin title) ada nulldalam kode di atas.

Contoh dengan rantai pengecualian

Terkadang aplikasi akan menangkap Pengecualian dan melemparkannya kembali sebagai penyebab Pengecualian lainnya. Ini biasanya terlihat seperti:

34   public void getBookIds(int id) {
35      try {
36         book.getId(id);    // this method it throws a NullPointerException on line 22
37      } catch (NullPointerException e) {
38         throw new IllegalStateException("A book has a null property", e)
39      }
40   }

Ini mungkin memberi Anda jejak tumpukan yang terlihat seperti:

Exception in thread "main" java.lang.IllegalStateException: A book has a null property
        at com.example.myproject.Author.getBookIds(Author.java:38)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Caused by: java.lang.NullPointerException
        at com.example.myproject.Book.getId(Book.java:22)
        at com.example.myproject.Author.getBookIds(Author.java:36)
        ... 1 more

Yang berbeda dari yang satu ini adalah "Disebabkan oleh". Terkadang pengecualian memiliki beberapa bagian "Disebabkan oleh". Untuk ini, Anda biasanya ingin menemukan "akar penyebab", yang akan menjadi salah satu bagian "disebabkan oleh" terendah dalam jejak tumpukan. Dalam kasus kami, ini:

Caused by: java.lang.NullPointerException <-- root cause
        at com.example.myproject.Book.getId(Book.java:22) <-- important line

Sekali lagi, dengan pengecualian ini kita ingin melihat garis 22dari Book.javauntuk melihat apa yang mungkin menyebabkan NullPointerExceptionsini.

Contoh yang lebih menakutkan dengan kode perpustakaan

Biasanya jejak tumpukan jauh lebih kompleks daripada dua contoh di atas. Ini sebuah contoh (ini adalah contoh yang panjang, tetapi menunjukkan beberapa tingkat pengecualian berantai):

javax.servlet.ServletException: Something bad happened
    at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.example.myproject.ExceptionHandlerFilter.doFilter(ExceptionHandlerFilter.java:28)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.example.myproject.OutputBufferFilter.doFilter(OutputBufferFilter.java:33)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
    at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: com.example.myproject.MyProjectServletException
    at com.example.myproject.MyServlet.doPost(MyServlet.java:169)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
    at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:30)
    ... 27 more
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.example.myproject.MyEntity]
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:64)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2822)
    at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
    at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
    at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
    at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689)
    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344)
    at $Proxy19.save(Unknown Source)
    at com.example.myproject.MyEntityService.save(MyEntityService.java:59) <-- relevant call (see notes below)
    at com.example.myproject.MyServlet.doPost(MyServlet.java:164)
    ... 32 more
Caused by: java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1: duplicate value(s) for column(s) MY_COLUMN in statement [...]
    at org.hsqldb.jdbc.Util.throwError(Unknown Source)
    at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source)
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
    at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:57)
    ... 54 more

Dalam contoh ini, ada banyak lagi. Yang paling kami khawatirkan adalah mencari metode yang berasal dari kode kami , yang akan menjadi apa pun dalam com.example.myprojectpaket. Dari contoh kedua (di atas), pertama-tama kita ingin melihat ke bawah untuk penyebab root, yaitu:

Caused by: java.sql.SQLException

Namun, semua panggilan metode di bawah itu adalah kode perpustakaan. Jadi kita akan naik ke "Disebabkan oleh" di atasnya, dan mencari pemanggilan metode pertama yang berasal dari kode kita, yaitu:

at com.example.myproject.MyEntityService.save(MyEntityService.java:59)

Seperti pada contoh sebelumnya, kita harus melihat secara MyEntityService.javaonline 59, karena di situlah kesalahan ini berasal (kesalahan ini agak jelas apa yang salah, karena SQLException menyatakan kesalahan, tetapi prosedur debug adalah yang kita kejar).


3
@RobHruska - Dijelaskan dengan sangat baik. +1. Apakah Anda tahu ada parser yang mengambil jejak pengecualian sebagai string dan menyediakan metode yang berguna untuk menganalisis stacktrace? - seperti getLastCausedBy () atau getCausedByForMyAppCode ("com.example.myproject")
Andy Dufresne

1
@AndyDufresne - Saya belum pernah menemukan, tapi sekali lagi saya juga belum benar-benar melihat.
Rob Hruska

1
Perbaikan yang disarankan: jelaskan baris pertama jejak tumpukan yang dimulai dengan Exception in thread "main"dalam contoh pertama Anda. Saya pikir akan sangat membantu untuk menjelaskan bahwa baris ini sering disertai dengan pesan, seperti nilai variabel, yang dapat membantu mendiagnosis masalah. Saya mencoba mengedit sendiri, tetapi saya berusaha menyesuaikan ide-ide ini dengan struktur jawaban Anda yang ada.
Code-Apprentice

5
Juga java 1.7 menambahkan "Ditekan:" - yang berisi daftar pengecualian yang ditekan jejak tumpukan sebelum menampilkan "Disebabkan oleh:" untuk pengecualian ini. Ini secara otomatis digunakan oleh try-with-resource build : docs.oracle.com/javase/specs/jls/se8/html/… dan berisi pengecualian jika ada yang dilemparkan selama penutupan sumber daya.
dhblah

Ada JEP openjdk.java.net/jeps/8220715 yang bertujuan untuk lebih meningkatkan kelengkapan terutama NPE dengan memberikan detail seperti "Tidak dapat menulis bidang 'nullInstanceField' karena 'this.nullInstanceField' adalah nol."
Mahatma_Fatal_Error

80

Saya memposting jawaban ini sehingga jawaban teratas (saat diurutkan berdasarkan aktivitas) bukanlah salah yang jelas-jelas salah.

Apa itu Stacktrace?

Stacktrace adalah alat debugging yang sangat membantu. Ini menunjukkan tumpukan panggilan (artinya, tumpukan fungsi yang dipanggil ke titik itu) pada saat pengecualian tanpa pelemparan dilemparkan (atau saat stacktrace dihasilkan secara manual). Ini sangat berguna karena tidak hanya menunjukkan di mana kesalahan terjadi, tetapi juga bagaimana program berakhir di tempat kode itu. Ini mengarah ke pertanyaan berikutnya:

Apa itu Pengecualian?

Pengecualian adalah apa yang digunakan lingkungan runtime untuk memberi tahu Anda bahwa terjadi kesalahan. Contoh populer adalah NullPointerException, IndexOutOfBoundsException atau ArithmeticException. Masing-masing disebabkan ketika Anda mencoba melakukan sesuatu yang tidak mungkin. Sebagai contoh, NullPointerException akan dilemparkan ketika Anda mencoba melakukan dereferensi objek-Null:

Object a = null;
a.toString();                 //this line throws a NullPointerException

Object[] b = new Object[5];
System.out.println(b[10]);    //this line throws an IndexOutOfBoundsException,
                              //because b is only 5 elements long
int ia = 5;
int ib = 0;
ia = ia/ib;                   //this line throws an  ArithmeticException with the 
                              //message "/ by 0", because you are trying to
                              //divide by 0, which is not possible.

Bagaimana saya harus berurusan dengan Stacktraces / Pengecualian?

Pada awalnya, cari tahu apa yang menyebabkan Pengecualian. Coba googleing nama pengecualian untuk mencari tahu, apa penyebab pengecualian itu. Sebagian besar waktu akan disebabkan oleh kode yang salah. Dalam contoh yang diberikan di atas, semua pengecualian disebabkan oleh kode yang salah. Jadi untuk contoh NullPointerException Anda dapat memastikan bahwa atidak pernah nol pada waktu itu. Anda dapat, misalnya, menginisialisasia atau memasukkan cek seperti ini:

if (a!=null) {
    a.toString();
}

Dengan cara ini, garis menyinggung tidak dieksekusi jika a==null . Hal yang sama berlaku untuk contoh lainnya.

Terkadang Anda tidak dapat memastikan bahwa Anda tidak mendapatkan pengecualian. Misalnya, jika Anda menggunakan koneksi jaringan dalam program Anda, Anda tidak dapat menghentikan komputer dari kehilangan koneksi internetnya (mis. Anda tidak dapat menghentikan pengguna untuk memutuskan koneksi jaringan komputer). Dalam hal ini perpustakaan jaringan mungkin akan melempar pengecualian. Sekarang Anda harus menangkap pengecualian dan menanganinya . Ini berarti, dalam contoh dengan koneksi jaringan, Anda harus mencoba untuk membuka kembali koneksi atau memberi tahu pengguna atau sesuatu seperti itu. Juga, setiap kali Anda menggunakan tangkapan, selalu hanya menangkap pengecualian yang ingin Anda tangkap, jangan gunakan pernyataan tangkapan luas seperticatch (Exception e)itu akan menangkap semua pengecualian. Ini sangat penting, karena jika tidak, Anda mungkin secara tidak sengaja menangkap pengecualian yang salah dan bereaksi dengan cara yang salah.

try {
    Socket x = new Socket("1.1.1.1", 6789);
    x.getInputStream().read()
} catch (IOException e) {
    System.err.println("Connection could not be established, please try again later!")
}

Mengapa saya tidak menggunakannya catch (Exception e)?

Mari kita gunakan contoh kecil untuk menunjukkan mengapa Anda tidak harus menangkap semua pengecualian:

int mult(Integer a,Integer b) {
    try {
        int result = a/b
        return result;
    } catch (Exception e) {
        System.err.println("Error: Division by zero!");
        return 0;
    }
}

Apa kode ini coba lakukan adalah untuk menangkap yang ArithmeticExceptiondisebabkan oleh kemungkinan pembagian dengan 0. Tetapi juga menangkap kemungkinan NullPointerExceptionyang dilemparkan jika aatau bsedang null. Ini berarti, Anda mungkin mendapatkan NullPointerExceptiontetapi Anda akan memperlakukannya sebagai ArithmeticException dan mungkin melakukan hal yang salah. Dalam kasus terbaik Anda masih merindukan bahwa ada NullPointerException. Hal-hal seperti itu membuat proses debug jauh lebih sulit, jadi jangan lakukan itu.

TLDR

  1. Cari tahu apa penyebab pengecualian dan perbaiki, sehingga tidak membuang pengecualian sama sekali.
  2. Jika 1. tidak memungkinkan, tangkap pengecualian spesifik dan tangani.

    • Jangan hanya menambahkan try / catch dan abaikan saja pengecualian! Jangan lakukan itu!
    • Jangan pernah gunakan catch (Exception e), selalu dapatkan Pengecualian tertentu. Itu akan menghemat banyak sakit kepala.

1
penjelasan yang bagus mengapa kita harus menghindari bug masking
Sudip Bhandari

2
Saya memposting jawaban ini sehingga jawaban teratas (ketika diurutkan berdasarkan aktivitas) bukan salah satu yang jelas salah saya tidak tahu yang mana yang Anda bicarakan karena ini mungkin sudah berubah sekarang. Tetapi jawaban yang diterima jelas lebih menarik;)
AxelH

1
Yang saya maksud sudah dihapus sekarang, sejauh yang saya tahu. Pada dasarnya dikatakan "coba saja {} catch (Exception e) {} dan abaikan semua kesalahan". Jawaban yang diterima jauh lebih tua dari jawaban saya, jadi saya bertujuan untuk memberikan sedikit pandangan berbeda tentang masalah ini. Saya tidak berpikir itu membantu siapa pun untuk hanya menyalin jawaban orang lain atau untuk menutupi apa yang sudah dibahas orang lain dengan baik.
Dakkaron

Itu menyesatkan untuk mengatakan "Jangan tangkap pengecualian", itu hanya satu kasus penggunaan. Contoh Anda bagus, tetapi bagaimana dengan di mana Anda berada di bagian atas loop utas Anda (dalam menjalankan)? Anda harus SELALU menangkap pengecualian (atau mungkin Throwable) di sana dan mencatatnya agar tidak hilang secara tidak terlihat (Pengecualian yang dilemparkan dari proses umumnya tidak dicatat dengan benar kecuali Anda telah mengatur utas / pencatat untuk melakukannya).
Bill K

1
Saya tidak memasukkan kasus khusus ini karena ini hanya masalah multithreading. Dalam threading tunggal pengecualian bocor membunuh program dan dicatat secara nyata. Jika seseorang tidak tahu cara menangani pengecualian dengan benar, mereka biasanya juga tidak tahu cara menggunakan multithreading.
Dakkaron

21

Untuk menambah apa yang disebutkan Rob. Mengatur titik-titik istirahat pada aplikasi Anda memungkinkan untuk pemrosesan tumpukan secara bertahap. Ini memungkinkan pengembang untuk menggunakan debugger untuk melihat pada titik yang tepat metode ini melakukan sesuatu yang tidak terduga.

Karena Rob telah menggunakan NullPointerException(NPE) untuk menggambarkan sesuatu yang umum, kami dapat membantu menghapus masalah ini dengan cara berikut:

jika kita memiliki metode yang mengambil parameter seperti: void (String firstName)

Dalam kode kami, kami ingin mengevaluasi yang firstNameberisi nilai, kami akan melakukan ini seperti ini:if(firstName == null || firstName.equals("")) return;

Hal di atas mencegah kita dari menggunakan firstNamesebagai parameter yang tidak aman. Karenanya dengan melakukan pemeriksaan nol sebelum memproses kami dapat membantu memastikan bahwa kode kami akan berjalan dengan baik. Untuk memperluas contoh yang menggunakan objek dengan metode, kita dapat melihat di sini:

if(dog == null || dog.firstName == null) return;

Di atas adalah urutan yang tepat untuk memeriksa nol, kita mulai dengan objek dasar, anjing dalam kasus ini, dan kemudian mulai berjalan di pohon kemungkinan untuk memastikan semuanya valid sebelum diproses. Jika pesanan dibatalkan, NPE berpotensi terlempar dan program kami akan macet.


Sepakat. Pendekatan ini dapat digunakan untuk mencari tahu referensi mana dalam suatu pernyataan nullketika sebuah NullPointerExceptionsedang diperiksa, misalnya.
Rob Hruska

16
Ketika berhadapan dengan String, jika Anda ingin menggunakan metode equals, saya pikir lebih baik menggunakan konstanta di sisi kiri perbandingan, seperti ini: Alih-alih: if (firstName == null || firstName.equals ("" )) kembali; Saya selalu menggunakan: if ((""). Equals (firstName)) Ini mencegah pengecualian Nullpointer
Torres

15

Ada satu lagi fitur stacktrace yang ditawarkan oleh keluarga Throwable - kemungkinan untuk memanipulasi informasi jejak stack.

Perilaku standar:

package test.stack.trace;

public class SomeClass {

    public void methodA() {
        methodB();
    }

    public void methodB() {
        methodC();
    }

    public void methodC() {
        throw new RuntimeException();
    }

    public static void main(String[] args) {
        new SomeClass().methodA();
    }
}

Jejak tumpukan:

Exception in thread "main" java.lang.RuntimeException
    at test.stack.trace.SomeClass.methodC(SomeClass.java:18)
    at test.stack.trace.SomeClass.methodB(SomeClass.java:13)
    at test.stack.trace.SomeClass.methodA(SomeClass.java:9)
    at test.stack.trace.SomeClass.main(SomeClass.java:27)

Jejak tumpukan yang dimanipulasi:

package test.stack.trace;

public class SomeClass {

    ...

    public void methodC() {
        RuntimeException e = new RuntimeException();
        e.setStackTrace(new StackTraceElement[]{
                new StackTraceElement("OtherClass", "methodX", "String.java", 99),
                new StackTraceElement("OtherClass", "methodY", "String.java", 55)
        });
        throw e;
    }

    public static void main(String[] args) {
        new SomeClass().methodA();
    }
}

Jejak tumpukan:

Exception in thread "main" java.lang.RuntimeException
    at OtherClass.methodX(String.java:99)
    at OtherClass.methodY(String.java:55)

2
Saya tidak tahu bagaimana perasaan saya tentang ini ... dengan sifat utasnya, saya akan menyarankan pengembang baru untuk tidak mendefinisikan jejak tumpukan mereka sendiri.
PeonProgrammer

15

Untuk memahami namanya : Jejak tumpukan adalah daftar Pengecualian (atau Anda dapat mengatakan daftar "Penyebab oleh"), dari Pengecualian yang paling permukaan (mis. Pengecualian Lapisan Layanan) ke yang paling dalam (mis. Pengecualian Basis Data). Sama seperti alasan kami menyebutnya 'tumpukan' adalah karena tumpukan adalah First in Last out (FILO), pengecualian terdalam terjadi di awal, kemudian rantai pengecualian menghasilkan serangkaian konsekuensi, permukaan Pengecualian adalah yang terakhir satu terjadi pada waktunya, tetapi kita melihatnya sejak awal.

Kunci 1 : Hal rumit dan penting yang perlu dipahami di sini adalah: penyebab terdalam mungkin bukan "penyebab utama", karena jika Anda menulis beberapa "kode buruk", ini dapat menyebabkan beberapa pengecualian di bawahnya yang lebih dalam dari lapisannya. Misalnya, kueri sql yang buruk dapat menyebabkan reset koneksi SQLServerException di bottem bukannya kesalahan syndax, yang mungkin hanya di tengah tumpukan.

-> Temukan akar penyebab di tengah adalah pekerjaan Anda. masukkan deskripsi gambar di sini

Kunci 2 : Hal rumit tapi penting lainnya ada di dalam setiap blok "Penyebab", baris pertama adalah lapisan terdalam dan terjadi di tempat pertama untuk blok ini. Contohnya,

Exception in thread "main" java.lang.NullPointerException
        at com.example.myproject.Book.getTitle(Book.java:16)
           at com.example.myproject.Author.getBookTitles(Author.java:25)
               at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

Book.java:16 dipanggil oleh Auther.java:25 yang disebut oleh Bootstrap.java:14, Book.java:16 adalah akar penyebabnya. Di sini melampirkan diagram mengurutkan jejak jejak dalam urutan kronologis. masukkan deskripsi gambar di sini


8

Hanya untuk menambah contoh lain, ada kelas dalam (bersarang) yang muncul dengan $tanda. Sebagai contoh:

public class Test {

    private static void privateMethod() {
        throw new RuntimeException();
    }

    public static void main(String[] args) throws Exception {
        Runnable runnable = new Runnable() {
            @Override public void run() {
                privateMethod();
            }
        };
        runnable.run();
    }
}

Akan menghasilkan jejak tumpukan ini:

Exception in thread "main" java.lang.RuntimeException
        at Test.privateMethod(Test.java:4)
        at Test.access$000(Test.java:1)
        at Test$1.run(Test.java:10)
        at Test.main(Test.java:13)

5

Posting lain menggambarkan apa itu stack trace, tetapi masih sulit untuk dikerjakan.

Jika Anda mendapatkan tumpukan jejak dan ingin melacak penyebab pengecualian, titik awal yang baik dalam memahami itu adalah menggunakan Java Stack Trace Console di Eclipse . Jika Anda menggunakan IDE lain mungkin ada fitur serupa, tetapi jawaban ini tentang Eclipse.

Pertama, pastikan bahwa Anda memiliki semua sumber Java Anda dapat diakses di proyek Eclipse.

Kemudian dalam perspektif Java , klik pada tab Konsol (biasanya di bagian bawah). Jika tampilan Konsol tidak terlihat, buka opsi menu Window -> Show View dan pilih Console .

Kemudian di jendela konsol, klik tombol berikut (di sebelah kanan)

Tombol konsol

dan kemudian pilih Java Stack Trace Console dari daftar drop-down.

Rekatkan jejak tumpukan Anda ke konsol. Ini kemudian akan memberikan daftar tautan ke kode sumber Anda dan kode sumber lainnya yang tersedia.

Ini yang mungkin Anda lihat (gambar dari dokumentasi Eclipse):

Diagram dari dokumentasi Eclipse

Panggilan metode terbaru yang dilakukan akan menjadi bagian atas tumpukan, yang merupakan baris teratas (tidak termasuk teks pesan). Turun tumpukan kembali ke waktu. Baris kedua adalah metode yang memanggil saluran pertama, dll.

Jika Anda menggunakan perangkat lunak sumber terbuka, Anda mungkin perlu mengunduh dan melampirkan proyek ke sumber Anda jika Anda ingin memeriksanya. Unduh toples sumber, di proyek Anda, buka folder Pustaka yang direferensikan untuk menemukan tabung Anda untuk modul sumber terbuka Anda (yang berisi file kelas) kemudian klik kanan, pilih Properties dan pasang toples sumber.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.