Bitva jazyků: Java versus C#

Na články z oblasti programovacích jazyků Java a C#, které jsem již publikoval, reagovali jejich čtenáři velmi živě...


Na články z oblasti programovacích jazyků Java a C#, které jsem již publikoval,
reagovali jejich čtenáři velmi živě a množství příspěvků hraničilo až s
"náboženskou" rivalitou zastánců z obou táborů. Zkusme se dnes realisticky, a
pokud možno objektivně, podívat na hlavní diskutované programátorské rozdíly a
nevýhody Javy ve srovnání s jazykem C#. Properties
Jedná se o koncept, který je určitě známý každému programátorovi, který
používal nebo používá vizuální vývojové nástroje. "Properties" jsou jistě
užitečná vlastnost, která umožňuje rychle přistupovat k vlastnostem objektů
stejně, jako bychom přistupovali ke členským proměnným dané třídy. Typickým
příkladem, známým asi každému programátorovi, je psaní kódu v JavaScriptu, kde
je právě tento koncept hojně využíván a díky němuž vývojář dokáže psát
jednoduchý a přitom plně funkční kód.
Jak tedy řeší Java a C# přístup ke členským proměnným? Níže uvedený příklad v
Javě (je ale platný např. i pro C++) ukazuje, jak lze pracovat s proměnnými
zapouzdřenými uvnitř třídy:
jmeno_objektu.setValue(jmeno_objektu.getValue() + 1);

Naproti tomu v C# lze pracovat s "properties":
jmeno_objektu.value++;

Je vidět, že kód je díky "properties" přehlednější, ale na druhou stranu člověk
může ztratit orientaci, kdy je volána metoda a kdy se přímo přistupuje ke
členské proměnné. To může být velmi důležité a nepříjemné chování například při
ladění při hledání chyby, kdy programátor přímo přistupuje k proměnné třídy,
která může být z historických důvodů veřejná, ale do které klient později chtěl
implementovat verifikační funkce.
Podle mého názoru je dobře, že tato funkcionalita není definována ani pro Javu,
ani pro C++, ale je k dispozici v C#. Díky umístění C# v produktové sadě
Microsoftu (Microsoft jej staví mezi Visual Basic a Visual C++) jsou
"properties" velmi výhodné, cílová skupina programátorů je na jejich použití
zvyklá a dokáže je náležitě ocenit a využít.

Enum
Enum je klasická vlastnost jazyka C a pro programátory, kteří jej znají, určitě
důležitá (spíše z pohledu zvyku a stylu psaní kódu, pokud mohu hodnotit dle své
vlastní zkušenosti). V Javě enum chybí, což je možná špatně, protože díky této
vlastnosti by bylo možné zjednodušit zápis kódu. Na druhou stranu se jedná o
porušení objektového návrhu jazyka. Enum totiž není třídou, ale v C# se staví
na její úroveň Enum lze definovat samostatně a nezávisle.
V C# bude definice vypadat například takto:
public enum Errors {ERROR1 = 1, ERROR2 = 2, ERROR3 = 3...};
Tímto je možné jednoduše definovat např. chybové kódy a snadno pak s nimi v
aplikaci pracovat. Oproti tomu Java je o něco těžkopádnější, a aby definovala
to, co jsem výše uvedl v příkladu pro C#, je nutný tento zápis:
public class Errors {
public final int ERROR1 = 1;
public final int ERROR2 = 2;
public final int ERROR3 = 3;
Toto chování je pochopitelně nevýhodné, a to proto, že v Javě kvůli neexistenci
enum musí kontrolu typové správnosti dělat pouze vývojář (nebo pak jen přes
"kontrolu" runtimových chyb). Oproti tomu C# nabízí možnost definovat enumeraci
konstant, kdy pak jejich správnost použití (alespoň typovou) kontroluje samotný
kompilátor. A to je výrazné urychlení a usnadnění vývoje.
Zde je příklad, jak C# může efektně pracovat s enumerací a využívat kompilátoru
k typové kontrole:


using System;
public enum ERRORS {SYS_DOWN=1000, SMALL_BUG=10, BIGGER_BUG=20, OK=0}; public
class TestTrida {
public static void Main() {
testError(ERRORS.BIGGER_BUG);
public static void testError(ERRORS err){
if (Enum.IsDefined(typeof(ERRORS), err)) {
Console.WriteLine(err.GetHashCode());
Obdobný příklad v Javě vypadá takto:
public class TestTrida {
public static final int SYS_DOWN = 1000;
public static final int SMALL_BUG = 10;
public static final int BIGGER_BUG = 20;
public static final int OK = 0;
public static void main(String[] args) {
testError(BIGGER_BUG);
public static void testError(int err){
if (err == SYS_DOWN || err == SMALL_BUG || err == BIGGER_BUG || err == OK) {
System.out.println(err);

Je vidět, že práce s enum může skutečně zjednodušit čitelnost kódu a hlavně
zefektivnit vývoj co se týče ladění.
Na druhou stranu je nutné na obhajobu Javy říci, že vytažení enum na úroveň
třídy je do jisté míry porušením objektového charakteru jazyka, a je těžké
zhodnotit, je-li to dobře, nebo ne. Asi nejvhodnější odpovědí na to, co je
lepší, je zvyk a styl psaní kódu konkrétního vývojáře.

Struct
V Javě jsou všechny třídy alokovány na haldě a primitivní datové typy v
zásobníku. To vede často k nepříjemným problémům, protože někdy jsou objekty
využívány jako primitivní datové typy (např. třídy obsahující jen chybové kódy
a hlášky). Tyto třídy jsou pak alokovány na haldě a systém se kvůli jejich
používání zpomaluje, protože "garbage collector" musí kontrolovat poměrně velké
množství objektů a referencí na ně a rozhodovat se o dealokaci. C# se tomuto
problému snaží vyhnout použitím struct, jež může nahradit klíčové slovo class.
Výsledkem je pak vznik objektu, který má charakter třídy, ale je alokován jako
primitivní datový typ tedy v zásobníku. Tato vlastnost pak může vést k
zefektivnění výkonnosti aplikace. Žel Java tento problém neřeší.

Příklad použití struct namísto class:

using System; struct Error
public string note; public int code;
public Error(string n, int x)
this.note = n; this.code = x;
public string getCode
return note;
public static void Main(string[] args) {
Error err1 = new Error("Nejaka chybova hlaska", 10); Console.WriteLine("Hlaska:
" + err1.getCode());
// u tridy by se zde kod nezkompiloval
Error err2 = new Error(); Console.WriteLine("Konstruktor bez parametru: " +
err2);


Delegáti
Mechanismus delegátů byl poprvé popsán Andersem Hejlsbergem (původně hlavním
architektem Borlandu a autorem Delphi, nyní pracuje pro Microsoft). Spor o
jejich použití začal uvedením ve Visual J++. Delegáti jsou podobní ukazatelům
na funkce z C/C++ a mohou být užiteční v mnoha situacích. Klasickým použitím,
které je známé programátorům v C/C++, je implementace obecných metod, kde se na
základě nějakých podmínek může předávat ukazatel na funkci poskytující
konkrétní implementaci.
Java v podstatě poskytuje jedinou možnost, jak delegáty napodobit, a to pomocí
rozhraní. Přesto se ale nejedná o delegáty v pojetí ukazatele na funkce,
protože rozhraní jsou svázána s konkrétní instancí třídy a nelze zde definovat
statické funkce.
Osobně si však myslím, že se jedná o styl, který nebude snadno pochopitelný pro
programátory ve Visual Basicu (a jiných 4GL prostředích), a to ne z pohledu
pochopení principu, ale vnitřního uvažování a přemýšlení v tomto způsobu psaní
kódu. Kromě toho je i hodně sporné, zdali se tímto konceptem vážně nenarušuje
objektový návrh. Odpověď zřejmě neexistuje, jak již ukázala několikaletá
odborná přestřelka mezi firmami Sun Microsystems a Microsoft.

Collections a příkaz foreach
Práce s collections má v C# několik hezkých vylepšení, mezi která určitě patří
příkaz foreach. Ten je známý programátorům ve Visual Basicu a v JavaScriptu,
kde se velmi efektivně využívá (viz příklady).

Příklad v Javě při práci s collection:
while (!collection.empty)
collection.get();
collection.next();
Příklad v Javě při práci s polem:
for (int i=0; i<array.length; i++)

Jak je vidět na příkladě, v Javě je nutné explicitně definovat pomocné proměnné
pro práci s collection/polem. C# naproti tomu umožňuje výše uvedený kód
implementovat takto:
foreach(typ_objektu o in collection) a foreach(typ_objektu i in pole) {...}
Aby bylo možné používat foreach, je nutné, aby programátor dodržel několik
podmínek. Především collection musí implementovat metodu GetEnumerator,
vracející Enumerator. U tohoto objektu pak je nutné implementovat metodu
MoveNext a "property" Current. Následující příklad ukazuje, jak je nutné
nadefinovat "collection", aby se s ní dalo takto zjednodušeně pracovat:

using System;
public class TestovaciCol
int[] polozky_pole;
public TestovaciCol
polozky_pole = new int[5] {1, 2, 3, 4, 5};
public MujEnumerator GetEnumerator
return new MujEnumerator(this);
public class MujEnumerator {
int index;
TestovaciCol pole;
public MujEnumerator(TestovaciCol param)
pole = param;
index = -1;
public bool MoveNextindex++;
return(index < pole.polozky_pole.GetLength(0)
public int Current
get
return(pole.polozky_pole[index]);
public class TestTrida
public static void Main
TestovaciCol col = new TestovaciCol;
Console.WriteLine("Hodnoty obsazene v testovacim poli:");
foreach (int i in col)
Console.WriteLine(i);

Jak je vidět, nemusí být použití foreach jednoduché, především tehdy, jestliže
si programátor musí svá "collection" implementovat sám. Ale pokud použije
některé z již hotových tříd, případně dostane k dispozici již naimplementované
své vlastní (např. od firemních systémových programátorů), je tato metoda velmi
efektivní a přehledná.
Autor pracuje jako vedoucí projektů u české společnosti Cleverlance.









Komentáře
K tomuto článku není připojena žádná diskuze, nebo byla zakázána.