(String) atau .toString ()?

89

Saya memiliki metode dengan Object oparameter.

Dalam metode ini, saya tahu persis ada Stringin "o" yang bukan null. Tidak perlu memeriksa, atau melakukan sesuatu yang lain. Saya harus memperlakukannya persis seperti sebuah Stringbenda.

Hanya ingin tahu - apa yang lebih murah - melemparkannya ke String, atau menggunakan Object.toString()? Atau sama dengan time- / cpu- / mem- price?

Pembaruan: Metode menerima Objectkarena ini adalah penerapan antarmuka. Tidak ada cara untuk mengubah tipe parameter.

Dan itu tidak mungkin nullsama sekali. Saya hanya ingin mengatakan bahwa saya tidak perlu memeriksanya untuk nol atau kosong. Dalam kasus saya, selalu ada string yang tidak kosong.

Vugluskr
sumber
1
Di dunia .NET, kami mengukurnya dan ToString () lebih cepat. Mengingat alasan mengapa demikian, hal yang sama hampir pasti berlaku untuk JVM yang bergoyang.
Joshua

Jawaban:

73

casting ke String lebih murah karena tidak memerlukan panggilan fungsi eksternal, hanya pemeriksaan tipe internal.

euforia83
sumber
4
Sudahkah Anda mengujinya di beberapa JRE? Saya telah melihat hasil yang mengejutkan untuk persis situasi ini di .NET. Secara realistis saya ragu bahwa performa akan penting dalam kehidupan nyata - tetapi casting lebih baik dari perspektif pengkodean defensif.
Jon Skeet
Panggilan metode harus inline. Menggunakan obat generik untuk menghapus cast (eksplisit) akan menjadi yang terbaik.
Tom Hawtin - tackline
@ Jon Skeet: Saya setuju bahwa perbedaan dalam kinerja tidak akan banyak. @ Tom Hawtin: Karena jenis objek yang akan diterima tidak diketahui pada waktu kompilasi, saya tidak dapat melihat bagaimana pemanggilan metode dapat disisipkan. Bisakah Anda menjelaskan?
euforia83
@ euphoria83: Digarisbawahi oleh kompilator JIT, bukan oleh javac.
Michael Myers
Sebenarnya, tidak, metode tidak bisa sebaris. Jenis hanya dikenal sebagai Objek, dan implementasi sebenarnya bergantung pada jenis waktu proses. Mana yang lebih cepat masih tergantung pada implementasi, tetapi sejauh yang saya ingat (saya benar-benar mengujinya dengan microbenchmark pada satu titik), casting tampaknya lebih cepat. Ini bukan jawaban yang jelas: pemeriksaan jenis tidak selalu lebih cepat. Untuk tipe String itu bisa karena itu adalah objek (bukan antarmuka), dan yang terakhir pada itu.
StaxMan
45

Saya akan menggunakan pemeran. Itu memvalidasi "pengetahuan" Anda bahwa itu adalah string. Jika karena alasan apa pun Anda berakhir dengan bug dan seseorang mengirimkan sesuatu selain string, saya pikir akan lebih baik untuk memberikan pengecualian (yang akan dilakukan oleh pemeran) daripada terus mengeksekusi dengan data yang cacat.

Jon Skeet
sumber
37

Menurut renungan kinerja konyol: x.toString () vs (String) x

Pada akhirnya, hasilnya sangat jelas: setidaknya dua kali lebih cepat untuk mentransmisikan Object ke String daripada memanggil Object.toString ()

cletus
sumber
1
Saya menjalankan kode itu sekarang, perbedaannya dapat diabaikan (Mac, Java 8)
Stefan L
7

Jika Anda tahu Objek o adalah String, saya akan mengatakan melemparkannya ke String dan menerapkannya seperti itu. Memanggil toString () pada objek yang Anda tahu pasti adalah String mungkin akan menambah kebingungan.

Jika Object o bisa berupa apa saja selain String, Anda harus memanggil toString ().

Andy White
sumber
Ini jawaban yang benar untuk saya. Mengapa? Karena casting (string)Registry.GetValue...memunculkan pengecualian untuk mencoba mentransmisikan objek Int32, sedangkan Registry.GetValue...ToString()berfungsi seperti yang diharapkan.
gravitasi
3

Saya tidak akan terlalu peduli dengan kinerjanya, jika operasi ini dilakukan bahkan hanya beberapa ribu kali per detik - tidak ada perbedaan yang nyata.

Namun, saya akan khawatir tentang "mengetahui" masukannya. Anda memiliki metode yang menerima Objectdan Anda harus memperlakukannya seperti itu, yaitu Anda tidak boleh tahu apa-apa tentang parameter, selain itu mematuhi Objectantarmuka, yang kebetulan memiliki toString()metode. Dalam hal ini, saya sangat menyarankan menggunakan metode itu daripada hanya mengasumsikan apa pun.

OTOH, jika input selalu salah satu Stringatau null, cukup ubah metode untuk menerima Strings, dan periksa secara eksplisit untuk nulls (yang harus Anda lakukan kapan pun ketika berhadapan dengan non-primitif ...)

Henrik Paul
sumber
Saya mengatakan bahwa pertanyaan saya tidak memiliki arti yang berharga :) Saya hanya ingin tahu apa yang secara teori lebih murah. Tapi
terima kasih
Biaya akan bergantung pada seberapa efisien VM pada panggilan metode virtual vs pemeriksaan jenis. Itu khusus untuk penerapan.
Jon Skeet
2

Mengingat bahwa tipe referensi adalah Object dan semua Object memiliki toString () panggil saja object.toString (). String.toString () baru saja mengembalikan ini.

  • toString () adalah lebih sedikit kode untuk diketik.
  • toString () adalah lebih sedikit bytecode.
  • casting adalah operasi yang mahal VS panggilan polimorfik.
  • pemerannya bisa gagal.
  • Gunakan String.valueOf (object) yang hanya memanggil object.toString () jika bukan null.
mP.
sumber
1

Jika apa yang Anda miliki di "o" adalah String maka tidak banyak perbedaan (kemungkinan cast lebih cepat, tapi itu adalah implementasi VM / Library).

Jika "o" mungkin bukan String tetapi seharusnya String maka cast adalah yang Anda inginkan (tetapi Anda harus membuat metode ini mengambil String, bukan Objek).

Jika "o" bisa berupa tipe apa saja maka Anda harus menggunakan toString - tetapi pastikan untuk memeriksa null terlebih dahulu.

void foo(final Object o)
{
    final String str;

    // without this you would get a class cast exception
    // be wary of using instanceof though - it is usually the wrong thing to do
    if(o instanceof String)
    {
        str = (String)o;
    }    
}

atau

void foo(final Object o)
{
    final String str;

    // if you are 100% sure that o is not null then you can get rid of the else
    if(o != null)
    {
        str = o.toString();
    }
}

Saya lebih suka membuat kode yang terakhir sebagai:

void foo(final Object o)
{
    final String str;

    if(o == null)
    {
        throw new IllegalArgumentException("o cannot be null");
    }

    str = o.toString();
}
TofuBeer
sumber
2 potongan pertama tidak akan benar-benar dikompilasi ( finalvariabel mungkin belum diinisialisasi). Anda memerlukan elseyang akan membuat pengecualian atau menginisialisasi strsesuatu.
Bruno Reis
1

Saya menemukan anehnya bahwa cast lebih lambat daripada pencarian vtable yang tersirat oleh panggilan tostring.

Joshua
sumber
1

Tidak boleh ada 'string nol di o'. Jika o adalah nol, itu tidak mengandung string nol, itu hanya nol. Cukup periksa o untuk nol dulu. Jika Anda mentransmisikan atau memanggil ToString () pada null, Anda akan crash.

Ed S.
sumber
2
Mentransmisikan nol tidak akan macet. Ia bahkan tidak akan memunculkan NullPointerException, ia hanya akan memanggil null ke tipe baru. :)
Bombe