Diskuze: Rada?
V předchozím kvízu, Online test znalostí Java, jsme si ověřili nabyté zkušenosti z kurzu.
Luboš Běhounek Satik:23.9.2016 15:09
do nejakyho pole si uloz vsechny ty hodnoty 1,2,5,10,20,... a pak misto takhle natvrdo to projedes jednim cyklem cely
Erik Báča:23.9.2016 15:10
Použij tlačítko pro vložení zdrojáku... Pak se na to možná kouknu
Petr Štechmüller:23.9.2016 15:36
Za IF se nepíše středník
V posledním řádku dělíš jednickou, což je zbytečné...
A jen taková malá drobnost - název třídy piš s velkým písmenem, je to konvence
jinak s tím polem souhlasím - a mohl bys krásně aplikovat početní operaci převodu z desítkové do dvojkové soustavy - projíždíš pole a pokud se tam aktuálně maximální hodnota vleze, tak ji tak rozměníš (a myslím, že takhle aplikované je to i hezký začátečnický prográmek)
stačí si projít zdejší toturiály - až na zapouzdření je vřele
doporučuji!
Ale tak pro tvoji představu:
Můžeš mít k dispozici pole. Pole si můžeš představit, jako tabulku,
která má hlavičku a jen jeden řádek - něco takovéhoto:
POLE
0 1 2 3 4 5 6 7 8 9
4 7 4 2 -3 4 389 22 37 7
ve výše uvedeném poli máš hlavičku deseti čísel od 0 do 9 a hodnoty
jsou náhodná čísla.
hlavně si pamatuj, že v programování se všechno čísluje od nuly. 0 je
vždy první index a hlavně v poli nebo kolekci
A ještě bys měl vědět o poli jednu věc - že pole nemůže mít prázdné
hodnoty. Každý index v poli (to vrchní číslo) musí mít nějakou hodnotu.
Dnešní IDEčka tě na to sami upozorňují.
V kódu můžeš pole zapsat pomocí hranatých závorek za datovým typem,
např.:
final int[] field; //pole datového typu Integer, takže pole bude obsahovat pouze celá čísla
final double[] floatField; //pole datového typu double, takže budou v poli desetinná čísla (desetiny se v programování nepíší čárkou, ale tečkou - např.: 2.3 je správně, 2,3 je špatně. Čárka vždy odděluje parametry, takže to si zapamatuj, je to častá chyba začátečníků (ale IDEčka tě na ní upozorní, je to syntaktická chyba a tu si hlídají IDE. Běhové chyby vyhledáš z exceptionů (vyjímek) a logické chyby jsou nejhorší - ty musíš prostě najít sám. :) jen taková poznámka bokem.
final String[] args; //no a tohle pole Stringů, takže textového řetězce jsem zapsal tak, jak ses ním budeš často setkávat;) sám poznáš kdy a kde
všechna výše uvedená pole jsou stejná, akorát mají různý datový
typ. Ale práce je pak naprosto stejná;)
ALE! do pole nemůžeš zapisovat tak snadno, jako třeba do proměnné.
final int promenna = 33; //tohle je jednoduchý zápis definování (nebo inicializování či naplnění) proměnné (můžeš používat jeden z těchto tří výrazů - jsou to synonyma:)
final int[] pole = 33; //je chyba!! a dokonce i nesmysl. Pole je přesně definované a pokud bys chtěl pole plnit ručně, tak by to vypadalo asi takhle nějak, za pomocí složených závorek a určení velikosti pole:
final int[] pole = new int[9]{ -4, 2, 1, -98, 0, 44, 3984, 372,,-9};
U ručního zápisu pole si pamatuj:
- final nemusí být, to je spíš už můj zlozvyk z testů, takže ty se zatím nemusíš pídit co to znamená
- int[], String[], boolean[] atd. atd. prostě datový typ, ať už primitivní či objektový (to si dočti ve zdejších tutoriálech, co to znamená) a dvě hranaté závorky PRÁZDNÉ HRANATÉ ZÁVORKY!!!!! První hranaté závorky říkají, že se nejedná o proměnnou, ale o nějaké jednorozměrné pole (pro zajímavost, dvou nebo třeba tří rozměrné pole bys logicky podle toho zapsal takto: int[][], String[][][], ale to už je trošku vyšší lvl, i když to není tak těžké pochopit. Dvourozměrné pole je jednoduše tabulka:), ale zatím si hraj s obyčejným polem.
- pak je nějaký název pole (to jen dodržuj konvence - žádné háčky a čárky, ideálně anglický název a malé prnví písmenku + velbloudí notace)
- potom voláš klasický operátor = a new, kterým řeneš, že vytváříš nové pole (pole není obyčejná proměnná, je to vlastně objekt, proto se k němu musíš i tak chovat)
- potom přichází na řadu druhé hranaté závorky a do nich už napíšeš velikost pole (já třeba řekl, že bude mít 9 chlívečků a jak jsem řekl - počítač to bude brát, že to není 1-9, ale 0-8)
- no a pak složené závorky a do nich oddělíš čárkami ty hodnoty. Když budeš mít pole Stringů (String[]), tak nezapomeň všude psát uvozovky => String[] field = new String[3]{"A", "B", "c"};
- a na konci jako vždy středník
To je ruční zadávání, ale s tím pracujeme spíše víc my testeři,
protože když třeba validujeme nějaké hodnoty, tak si je musíme vymyslet a
vypsat. Spíš se ale pole používá víc, když ti to nějaká metoda předá.
Krásným příkladem je třeba split() split metoda u Stringu.
Když máš nějaký String, třeba (String slovo =
"ůdsjgfjgů#dprejtjrepi#dsůgahi"; tak si můžeš jednotlivé písmenka
"vysplitit" (rozdělit) metodou split a to ulížíš do pole Stringů -
předvedu:
String title = "ITnetwork is pretty good portal about IT section.";
String[] letters = title.split("");
// a kdybych teď třeba napsal:
System.out.println(letters[0]);
// tak mi vypíše output "I" (bez uvozovek, to říkám tady - jako že písmeno I)
A to mi připomíná:) jednu hodnotu z pole získáš právě takto -
napíšeš název pole, hranaté závorky a index té hodnoty - v examplu jsem
chtěl první hodnotu, tak jsem napsal nulu. Pole je dokonce tak šikovné, že
má třeba i takové metody, abys s ním mohl efektivně pracovat. Např.:
length() - to ti řekne, kolik je v tom poli indexů (poslední index je
pochopitelně length - 1, protože tu délku toho pole ti řekne celým
číslem, ale jak už jsem tuším že 2x zmínil - v poli pracujeme od 0,
takže ji tam musíš do toho počítat:) )
A další hodně užitečná metoda je lastIndex() - a snad tušíš, že to
vrátí poslední index, nehledě na to, jestli víš, jak je to pole velké. A
to samé třeba předposlední hodnota, tu zjistíš matematicky lastIndex() - 1
atd. atd. atd.
Pak máš KOLEKCI
Kolekce jsou speciální pole (jednorozměrné), se kterými už přímo
komunikuješ, jako s objektem. Výhoda kolekce je taková, že ji můžeš
dynamicky editovat. Pole ne - pole můžeš pouze jednou naplnit (metodou nebo
ručně) a pak už jen z něj sosáš data. Kolekce má přidávací,
odebírací metody a spoustu dalších. Velice jednoduchým příkladem kolekce
je tzv. List nebo ArrayList. Já osobně vždy pracoval s ArrayListy (array
sebere jako pole a list kolekce, takže takové zdvojení významu)
Pochopitelně jsou mezi kolekcí a polem ještě další rozdíli, ale prozatím
si vystačíš s tím, co ti tu uvádím.
Příklad práce s kolekcí:
final ArrayList<Integer> array = new ArrayList<>();
//do těchto špičatých závorek udáváš, s jakým datovým typem se bude pracovat. Ale pozor, nejde pracovat s primitivními datovými typy, pouze s objektovými. (tzn. že nemůžeš napsat<int> ale když už tak Integer. To samé Boolean a ne boolean a u double taky tak - prostě objektový datový typ a ani jeden z těch 8 primitivních)
A ještě další věc - kolekce potřebuje import, ale to ti IDEčka sami nabídnou;) Tuším že je to import java.util.ArrayList; protože kolekce je nástroj, ale nejsem si teď zcela jistý, ale to je teď i nepodstatné. Takže když máš zadeklarovanou a inicializovanou kolekci tak si s ní můžeš hrát - třeba takto:
public void method(){
array.add(555);
System.out.println(array.get(0)); //i tady se všechno počítá od 0 a tento výpis vrátí hodntou 555
System.out.println(array.size()); //tento výpis vrátí hodnotu 1, protože jsme tam metodou add přidali pouze jeden prvek
array.remove(0); //smaže prvek z indexu 0 (a kdyby tam byly další prvky, tak je "posune" o pozici blíž na začátek - jako třeba takhle:
array.add(765);
array.add(9 + 8); //klidně můžeš provádět i různé operace, ale tak, aby jejich výsledek měl ten správný datový typ té kolekce
array.add(-2);
//včil jsem přidal do kolekce 3 čísla (765, 17 a -2) jsou na indexech 0, 1 a 2. Nemůžou být zde díry - že bys třeba řekl že chceš mít kolekci a čísla budou na indexech 0 1 4... to nejde. To by potom ztrácela kolekce smysl.
//a jdem si hrát:)
System.out.println(array.size()); //output bude 3 (jsou tam 3 prvky)
System.out.println(array.get(1)); //output bude 17, protože chceme prvek s indexem 1
System.out.println(array.get(size() - 1)); //output bude -2, protože chceme index vypočítaný z velikosti pole (to je 3) a -1, což je 2
System.out.println(array.get(size()); //output bude hodně červený a bude v něm na prnvím řádku ArrayOutOfIndex exception nebo tak nějak a bude to hlásit, že chceme 4 hodnotu, ale pole zná jen 3
array.remove(1); //smažeme prvek s indexem 1, což je v našem případě 17. Kolekce pak sama posune všechny indexy i s jejich prvky o jedno "dopředu" (pochopitelně od toho místa, kde to bylo smazané)
//takže sice jsem smazal prvek s indexem 1, ale kdybych teď napsal:
System.out.println(array.get(1)); //tak mi to vrátí -2 (hodnota, která byla předtím na indexu 2)
//no a když se naseru, tak napíšu:
array.removeAll(); //a je klid:) nemusím snad popisovat, co to udělá, přišla na to i moje mamka, takže je to opravdu jednoduché
}
Kolekce je výhoda třeba když pracuješ s vlákny nebo s hodnotami, které se zadávají v průběhu programu na různých místech nebo se s jejich zadáváním počítá furt dokola.
Takže pole nemůžeš měnit, pouze naplnit a získávat z něj hodnoty
Kolekci můžeš naplnit (dokonce by to šlo i přes cyklus stejně jako u pole,
ale třeba když bys chtěl splitit řetězce, jak jsem ukazoval, tak by byla
kokotina na to používat kolekci. Chudák procesor nemá na starost jen
ukládání dat do haldy;)
No a ještě existuje něco podobného jako arrayList, ale tam už
nezáleží na vzestupném pořadí indexů v hlavičce. Dokonce to anihlavičku
nemá - má to klíč a hodnotu. Říká se tomu mapa (třída Map) a je to
vlastně taková mini databáze. Obsahuje klíč a kněmu hodnotu. to jaký si
vymyslíš klíč a hodnotu, jakého budou datového typu, to záleží na
tobě, ale pochopitelně můžeš mít pouze jednu mapu s jedním datovým typem
u klíče. nemůžeš si třeba říct, že by byl jeden klíč String, druhý
int (teda.... šlo by, aby byl jeden String, druhý Integer a společný datový
typ by byl Object, ale tak doufám, že nechceš být prase!)
Zápis jednoduché mapy je trošku podivný, ale připomíná zápis
ArrayListu:
final Map<Integer,String> map = new HashMap<Integer, String>();
no... jen ve zkratce. Na rozdíl od ArrayListu má mapa v té závorce dva
parametry - jak jsem řekl, jeden je K (key, klíč) a druhý V (value, hodnota)
(tak se to píše i v dokumentacích - Map<K,V>)
tam s ivyber, co se ti líbí, já jsem třeba řekl, že klíče budou celá
čísla a hodnoty budou řetězce:)
Pak je pochopitelně název a inicializace mapy.
Je tu trošku něco podivného - Prvně říkám, že chci mapu datového typu
Map a pak vytvářím HashMap....
HashMap je to samé jako mapa, ale nemůžeš vytovřit obyčejnou mapu,kdyby
tam bylo jen = new Map<>, tak by to ztrácelo smysl a hlavně by to byla
jen trošku kombinovanější kolekce.Hash znamená, že uvnitř té mapy se
data nějak zamotají (to se používá třeba při zabezpečení). A abys
dostal správnou hodnotu z toho "chuchvalce" dat, tak musíš mít správný
klíč.
takže kdybych pokračoval v tom příkladu, tak metodou put() řeknu, že chci zadat nějakou hodnotu s klíčem:
map.put(766658, "3 offers during fire: git commit!, git push!, leave building!");¨
map.put(0, "ou shit");
tak - teď jsem do klíčů 0 a 766658 ulžil nějaká data. a já se ho můžu zkoušet zeptat:
System.out.println(map.get(0)); //a output bude: ou shit
System.out.println(map.get(1)); //a output bude: null
takže pole, kolekce a mapa - snad to trošku jde poznat, jaký je v tom rozdíl. Pochopitelně takových podobných nástrojů jsou mraky, ale tohle jsou asi tři nejzákladnější Ostatní jsou už spíš specifikace těchto tří (jako např. dvourozměrné pole:) )
Atrament:23.9.2016 22:56
Zapomněls zmínit Concurrent kolekce a rovnou jsi mohl vysvětlit i vlákna a procesy
No a cykly:)
Máme 6 druhy cyklů:
For
For-each
While
Do-while
Rekurze
a zacyklit podmínky do sebe, ale to je jen příklad prasárny (ani to už
neumím, jen to uvádím, že to nějak jde, asi tak, jakože existuje
stupidSort:) )
Základ je For cyklus
důležitá je syntaxe - teď ti ukážu jak to vypadá:
for(int i = 0, i < 10;i++){
}
tak.... vypadá to složitě, ale po tom předchozím spamu mi věř, že to
projdu step by step:D
takže stejně jako třídy a metody, i cykly se skládají z hlavičky a
těla
- for Hlavička for cyklu začíná slovíčkem for (popravdě nešťoural jsem, proč zrovna for:) to si vygoogli nebo to tu někdo doplní, ale pamatuj, že prostě for (a není to fór:D))
- () kulatá závorka přestavuje "tělo" hlavičky.
Tak a teď menší vsuvka.
PAMATUJ, ŽE KAŽDÝ CYKLUS MUSÍ MÍT 3 PARAMETRY!!!!!!!!
a logicky bys je i odvodil, když se zeptáš, co potřebuješ k nějakému
opakování furt dokola:
1.) potřebuješ nějakou výchozí hodnotu - řekněme, že budeš třeba
opakovat 10 čísel, ale začneš od čísla 15 Takže pro nás by byla
výchozí hodnota 15
2.) potřebuješ vědět, do kdy to máš dělat, ať jak debil nezačneš
třeba od 0 a zkončíš u trilionů. Takže třeba určíme, že zkončíš,
až budeš mít číslo 30
3.) no a za třetí sice víš, že začínáš od 15 do 30, ale nevíš, jestli
jít po jedné, dvou nebo po patnácti. Takže to je ten třetí parametr - ten
nám řekne, o kolik to budeme zvyšovat
PS: snaž se to vždy i při zadávání parametrů takhle: 1. od kolika, 2.
DOKUD a 3. o kolik (když by sis třeba místo toho druhého například
říkal,ne dokud ale do, tak tě to může časem zavádět na blbé úvahy - a
věř že vím o čem mluvím, já byl ten blbec, který se nechal svést-.- ale
včil su šikovný tester z Moravy:) )
Takže teď už možná trošku chápeš tu hlavičku. Ve for cyklu je
zajímavost, že tady toto nejsou parametry, ale dá se říct takové "bloky"
toho cyklu. Proto se neoddělují čárkou, ale středníkem;)
takže jdeme na první for-cyklus (nebo taky for-loop loopa je cyklus:) )
začínáme tedy magickým slovíčkem for a kulatými závorkami:
for()
včil začneme těmi bloky, takže nejdřív si zadeklarujeme třeba proměnnoui a naplníme ji hodnotou 15 (to je to, co už umíš) a dáme V ZÁVORCE ZA TENTO BLOK středník!!!!!! NE ZA KULATÉ ZÁVORKY, TAM ANI NEPATŘÍ!!!! (tedy mohl by být, ale... o tom potom)
for( int i = 15 ; ) //mezer si dělej kolik chceš, jediné, kde by to vadilo, je v názvech, ale kolem názvů a mezer si dělej so chceš (tedy jen bílé znaky. a jestli nevíš co je bílý znak - ITNetwork a jedem od první lekce)
tak druhý blok je podmínka DOKUD ne do ale DOKUD. takže si to tak
řeknem:
"cyklus se bude furt opakovat DOKUD je hodnota i menší nebo rovna 30" NEBO
"cyklus se bude furt opakvoat DOKUD hodnota i není rovna 30" to si vyber sám,
co se ti líbí, ale častěji je ten první případ
Matematicky zapsáno: dokud je hodnota i (i) menší nebo rovna (<=) 30
(30)
takže bez těch keců kolem závorek máme: i <= 30 a to tam šoupnem jako
druhý blok:
for( int i = 15 ; i <= 30 ; ) //a zase středník za druhý blok
no a třetí blok je ta inkrementace nebo dekrementace. No... tyto dva
výrazy znamenají něco specifičtějšího, to ti řeknu za chvíli....
Takže zvolíme si třeba, že se bude i zvyšovat vždy o 3, ať je prdel,
takže výstup by měl být od 15 do 30 a po třech, takže bys měl mít
vypsaná čísla 15, 18, 21, 24, 27 a 30
zvyšování o několik je zase matematická úloha, stačí správně
mluvit:
"přičítám hodnotě i (i) k její původní hodnotě (což je i) + 3 (+3)
takže matematicky: i = i +3 (nová hodnota i se rovná stará hodnota i +
3)
no a takhle to zapíšeme do třetího bloku OVŠEM UŽ BEZ
STŘEDNÍKU!!!!!!!!!
for( int i = 15 ; i <= 30 ; i = i + 3 ) //závorka a hlavičku máme dokončenou
Teď už jen přidáme tělo (jako vždy složenými závorkami)
for(int i = 15;i<=;30;i=i+3){
}
a máme hotový cyklus. Do těla pak napiš, aby vypsal hodnoty i
System.out.println(i);
Zkus si třeba zaexperimentovat - když nenapíšeš třeba i<=30, ale jen
i<30, nebo když napíšeš, že i = 31 v tomto případě - co se asi
stane:) nebo že nebudeš zvyšovat o součty 3,ale násobky 3 (násobení je
hvězdičkou* a dělení /, ale bacha, uvědom si, žekdyž dělíš nebo
odčítáš, že podmínka musí být zapsána jinak:) Jeslti nejsi úplný
tukan, tak ti to dojde - stačí správě mluvit a říkat si, co vlastně
děláš (a proto tak dbám, abys to správně říkal)
tak ještě k tomu třetímu bloku....
Java je chytrý jazyk a existují i různé finty, jak si ušetřit zápis.
Např.: když napíšeš jako jsme to psali předtím (i = i + 3) tak tam
píšeš dvakrát i a jak něco v programování píšeš stejné a víckrát,
je to hnus. Např.: tento konrkténě příklad by se dal zkrátit tak, že bys
vynechal to i za rovná se a to plusko dal za to první i a před rovná se.
Prostě si zapamtuj, že i = i + 3 je to samé, jako i += 3 Java to pochopí a
ty vypadáš drsně:)
Pochopitelně to tak funguje s jakoukoliv operací. Např.: i *= 99 atd.
ale pozor - záleží hodně na to pořadí před
rovnítkem!!!!!!!!!!!!!!!!!!!
pokud napíšeš i += 3, tak Java chápe, že má nejdřív k nějakému číslu
přičíst 3 a pak vykonat nějakou operaci.
Kdybys napsal i =+ 3, tak nejdřív vykoná operaci a pak až přičte 3. Což
by třeba dělalo s některými cykly hodně velký problém! takže pozor na
to.
Znamínka okolo rovnítka jsou vcelku složitější a přejdi k tomu radši
až po nějaké praxi. Ale existuje ještě jedna finta v programování, kterou
jsem tu už nakousl a ukázal v prvním příkladu cyklu:
říká se tomu:
INKREMENTACE a
DEKREMENTACE
(a nemá to nic společného s exkrementy, to někteří developeři
vytvářejí, ale to je zase něco jiného:) )
**Inkrement znamená navýšení
dekrement zase snížení
**
Prostě co zvyšuješ (ať už plusem, nebo násobením nebo různými
výpočty) tak je inkrementace
když naopak jakkoliv snižuješ, je to dekrementace
A existují dva velmi příjemné zápisy ve dvou zvláštních
případech
Dost často se stává (třeba zrovna pro procházení všech prvků v poli),
že potřebuješ zvyšovat/snižovat pouze o jedničku. Takže bys to psal furt
dokola jak osel i = i +/- 1
Ve všech jazycích se používá pro sčítání a odčítání (násobení a
dělení NE) zjednodušený zápis:
i = i + 1 je to samé, jako i++
i = i - 1 je to samé jako i--
PS: nemá to nic společného s c++, i kdyby sis to céčko dal místo ička a
takhle to zapsal, ale s jazykem c++ toto nesouvíisí:)
Ještě bych měl trošku říct, proč i..... je to takový nejčastější případ - právě kvůli té Inkrementaci - to je takový nejobecnější příklad cyklu:
for(int i = 0;i<10;i++){´
System.out.println(i);
}
tento kód vypíše čísla od 0 do 9 a je na to dokonce v netbeansech klávesová zkratka, která ti vytvoří přesně takovýto for cyklus (když chceš třeba na rychlo otestovat část pole a tak) Proto se používá i, a když máš cyklus v cyklu, tak "i" a "j". Ale můžeš použít jakýkoliv název, třeba i fň:) nebo auto - je to obyčejná proměná a ty s ní nějak pracuješ.
NO.... to byl první cyklus - for a už je tu spam jak blázen:D
For cyklu je hodně podobný while cyklus. dá se říct, že bys ho dokázal
zapsat stejně - ukážu ti dva stejné cykly, ale jeden for a jeden while:
for(int i = 100;i>=0;i--){
System.out.println(i);
}
int i = 0;
while(i>=0){
System.out.println(i);
i--;
}
Pozor!!! zrovna v tomto případě - napíšeš-li tento while před for, tak
ti to vyhodí chybu, protože ve for cyklu bys deklaroval novou proměnnou i,
kterou ovšem deklaruješ lokálně "nad" tím cyklem, to jen na
upozornění!
Jinak vidíš, že v tomto případě není žádná změna - zase tři
bloky,akorát že si tu proměnnou připravuješ mimo ten cyklus (právě to je
jeden z hlavních rozdílů mezi forkem a whileem - while cyklus může
začínat od hodnoty, kterou třeba někdo zadá nebo ji někde nějak později
získáš. For vstupní hodnotu nastavuješ ty jako dev/tester. while má v
závorce jen jeden blok a to je podmínka DOKDY, nebo DOKUD platí. A
inkrementaci si zařizuješv těle toho cyklu. to se třeba hodí, když máš
případ, že chceš ještě na začátku toho cyklu pracovat s vypočítanou
hodnotou, kterou sis vypočítal na konci těla. A až ji použiješ, tak teprve
inkrementuješ. Já to třeba akorát přesně tak dělám v tetrisu:) zatím co
mi jedna kostička padá - já si potom vygeneruji novou kostičku a na
začátku cyklu ji předeám,aby padala a mezi tím si vytvořím novou atd.
furt do kola (cyklus)
While je ještě specifický tím, že je hodně dá se říct
"uživatelský" zrovna tady v prvních tutoriálech ho krásně využívají -
kdy vlastně se dá říct, že while cyklus bude probíhat DOKUD uživatel
nezmění nějakou hodnotu, nebo dokud uživatel nezmačkne Alt + F4
Šlo by to tak psát i u for cyklu, ale to by pak vypadalo takto:
for(;UZIVATEL_NEZMACKL_KLAVESU_M;){
}
//zatím co while:
while(UZIVATEL_NEZMACKL_KLAVESU_M){
}
//tam ty středníky nemá a vypadá to líp. Oba fungují, ale je o ty středníky (jinak přečteš správně tuhle podmínku, kterou oba mají?:) schválně jestli si vzpomeneš na to důležité slovíčko:)
Tak třetí cyklus je DO-WHILE cyklus,který představuje v podstatě while cyklus,ale ještě navíc s tělem DO, takže zápis vypadá následovně:
int i = 0;
do{
System.out.println("Jů hele a do prdele!");
}while(i > 3)
schválně jsem to napsal takhle!
Když se na to pozorně podíváš, tak bez toho do, které zatím nevnímáme,
bychom to přečetli:
"hodnota "i" je 0. Opakuj cyklus while DOKUD je hodnota i větší než 3" To je
kokotina co? tak ona je 0 a on to má opakovat, dokud je hodnota stále větší
než 3 - což není ani jednou.
A TO JE TEN ROZDÍL!!!! mezi while a do-while. i kdybychom v cyklu pracovali s
hodnotou, která má být naplněná, ale není a to je třeba chyba, tak mi
chceme,aby ASPOŇ JEDNOU ten cyklus prošel! prostě nesere nás, že podmínka
není splněná, my to chceme jednou projít, tečka konec diskuze!!
no a proto on udělá do, ok, tak já vám to jednou pustím, ale pak neplatí
podmínka.
(trošku jsem se teď prokecl - ano jak devy, tak testři, jsou debilové a povídají si s počítačem:) akorát, že on vrací zprávy typu get a jejich znění je v hodnotách:) - např.: taková aspoň u mě každodenní konverzace s počítačem: "ty kokote, proč vracíš null ??!!!!!??":)
Takže for, je základ, while je uživatelský,do-while musí aspoň jedno
uproběhnout
Potom je tzv. for-each (ano, dalo by se to tak i přeložit - "pro každého")
To zase navážu na ten minulý spam. Asi by ti došlo, že abys zjistil
všechny hodnoty v poli a nechal si je třeba vypsat nebo bys hledal hodnotu,
která přdstavuje dejme tomu písmenko "b", tak bys to nechal projet cyklem.
Např.:
String slovo = "ůvjdsssssgdsjdsjjjgdasggjsajsgkůvjdsssssgdsjdsjjjgdasggjsajsgkdkgdkg";
//a já chci vědět, na kolikátém indexu je první písmeno "a", tak udělám třeba takvový for cyklus:) nebo while - tady je to jedno, jaký bys použil, ale do while je teď na hovno, protože to projde určitě víckrát, takže to nepotřebujeme
String[] pole = slovo.split(""); //jo ještě k tomu splitu - do závorky mezi uvozovky zadáváš, čím chceš to slovo rozdělit, tak třeba kdybys tam dal tečku (".") tak řekneš, že chceš rozdělit slovo natolik dílů, kolik je mezi nimi teček - tak třeba slovo "ůldfsů.fůsjfj.ůljf" bys rozdělil na tři díly a to pole by mělo 3 prvky. No a když tam dávám jen prázdné uvozovky, tak chci rozdělit žádným parametrem - proto to bere všechna písmena jako a tolik bude mít to pole indexů
String pismenoA; //teď si nejsem jistý jestli by nechtěla Java totu proměnnou inicializovat:O kyžtak by to bylo String pismenoA = ""; jakože je zatím prázdný řetězec
for(int i = 0; pismenoA.equals("a") ;i++) { //jen tak mimochodem:) hádej proč začínáme od 0 a ne od 1:) A jinak vidíš - zadávám podmínku a nemusí to být s íčkem. Já chci prostě najít první písmeno A - tak takovou dám podmínku. To equals - tose používá pro porovnání řetězců - je to vlastně to samé, jako bych napsal pismenoA == "a" (při porovnání se používají dvě rovnítka, protože jedno rovnítko přiřazuje nějakou hodnotu proměnným nebo neměnným:)
pismenoA = pole[i];
if(pismenoA.equals("a"){
System.out.println(i);
}
}
A až to najde "a", tak to skončí a vypíše index (když jdem od nuly, tak
index pole je stejný jako íčko:) )
PS: třeba konkrétně toto je diskutabilní otázka,jestli tam rvát podmínku
(to je to if) a nebo si dřív deklarovat nějakou proměnnou typu int a vždy
ji naplňovat novým íčkem (to by vypadlo jednoduše takhle: proměnná = i;
no a jak by ten cyklus skončil, tak bych už tu poslední hodnotu měl v té
proměnné a použil ji a nemusel bych dělat podmínku.
Osobně jsem byl vždy pro rychlejší řešení, ale co začínám nabírat zkušenosti v profi firmě (hlavně od jednoho borce, u kterého jsem si jistý, že by bez problémů hacknul třeba i databázi Pentagonu) tak se "přeučuju" návyky. Není prý vždy nejlepší psát všechno zrychlenými metodami - pak se neví, co se čím chtělo dokázat a kód začíná být hůř čitelný. Prioritou je psát kódy tak, aby je po tobě nemusel nikdo luštit, ale aby mrknul a updatoval. Ale to jen taková poznámečka bokem - takhle třeba uvažují ITáci, tak abys měl simple example:)
No a teď proč jsem psal tento příklad. Takhle by se dalo procházet jak
pole, tak kolekce a nešikovně i mapa (nešikovně asi chápeš proč - spousta
hodnot by byla null). No ale, máš-li pole nebo kolekci!! (u mapy to nejde),
kde máš postupně seřazené indexy a máš jistotu, že žádný z indexů
nemůže být prázdný (prostě to nejde - viz článek výš), tak můžeš
použít ten for each - cyklus pro každého. Je to lepší varianta v tom, že
nepoužíváš žádné proměnné, ale rovnou saháš na tu konkrétní hodnotu
(je to vlastně for cyklus, ale zkrácený zápis)
Existují dva zápisy for-each:
for(Integer number : array){
}
toto je první a jednodušší zápis, i když se nepodobá ani jednom ze zmíněnýh tří cyklů. Jde vlastně o to, že ty pracuješ s nějakou konkrétní kolekcí - to je tady array. (budeme vycházet že v tom máš integery, takže sis předtím deklaroval kolekci, takto:
ArrayList<Integer> array = new ArrayList<>();
a nastrkals do něj nějaké hodnoty pomocí metody add().
Tak ukážu ti ještě, jak bys to mohl udělat obyčejným for cyklem:
for(int i = 0;i<array.size();i++){
}
tento cyklus bys přečetl tak, že bys začal od indexu 0 a procházel bys
kolekci po jednom indexu až na konec. Pokud potřebuješ takhle projít celou
kolekci a ne třeba jen půlku z nich (pokud to není na celou kolekci, musí se
použít buď for nebo while, a ne for-each cyklus) tak je výhodnější
použít ten for-each
for-each je zkrácená verze právě tohoto for cyklu.
Je to cyklus, který ví, že půjde po jednom indexu přes celou kolekci, proto
nepotřebuje uvádět ten třetí blok. Ví dokonce, že půjde od prvního
indexu až po poslední v kolekdi, proto nepotřebuje ani první ani druhý
blok.
Jenže musí mít v hlavičce aspoň nějaký parametr. tady se zcela
vyjímečně oddělují dva parametry dvojtečkou. Tak se i for-each dá lehce
poznat.První parametr je deklarace proměnné, která má stejný datový typ,
jakého je celá kolekce nebo pole. Ale nesmíš ji naplňovat - to už si
cyklus udělá sám za tebe. Ty jen musíš deklarovat tu proměnnou, abys ty
měl s čím pracovat:) (jinak by sice cyklus prošel, ale ty by ses nemohl ani
dívat na výpis, prostě by cyklus prošel tak, že by se počítač podíval
na prvky a řekl si: "hezké moc hezké a co já s tím?":)
For-each ti v každém průchodu do té proměnné nastaví další a další
index - prostě tu proměnnou při každé své inkrementaci přepíše další
hodnotou indexu, který je o jedničku vyšší.
No a co si s tím uděláš ty - to je už tvoje věc
Takže tento for-each vypíše naprosto všechny prvky z celé kolekce a je mu
jedno, jestli jich je tam 13 nebo 100 000:
for(Integer number :array){
System.out.println(number);
}
a abys pracoval s větším objemem dat:) zkus si tohle:
ArrayList<Integer> array = new ArrayList<>();
for(int i = 0;i<1000000;i++){
array.add(i);
}
for(int i = 0;i<array.size();i++){
System.out.println(array.get(i));
}
for(Integer kikiriki:array){
System.out.println(kikiriki);
}
první cyklus ti naplní kolekci milionkem dat (možná se ti sekne kompl
) no a ty další dva
udělejaí naprosto to samé - vypíšou potsupně hodnoty té kolekce. Takže
tady můžeš vidět, že v tomto případě je mezi for cyklem a for-each
cyklem rozdíl v tom, že for-each je přehlednější a rychleji zapsaný:)
Ale kdybys změnil u toho for vypisovacího for cyklu hodnotu z i++ na i += 2
(nebo i = i + 2) tak to už je for each nahraný. Taky by to tak uměl přiadala
by se mu podmínka, ale zbytečně by načítal (v tomto případě o půl
milionu víc dat, než by bylo potřeba) a se vší úctou, to už je kurva
rozdíl.
Druhý zápis for-each je trošku složitější.Dělá naprosto to samé, ale je to jiný zápis, takže ho uvedu jen pro info:
array.stream().forEach((number) ->{
System.out.println(number);
});
abych se přiznal -taky nevím všechno a zatím jsem nezkoumal, proč a co je vlastně ten strream. Jen jsem se to naučil a popravdě z jednoho jediného důvodu - sere mě, když mi netbeans píše nějaké warningy a jsem líný je vypínat
No a na závěr - Rekurze
rekurze je vlastně metoda, která vola samu sebe.
Např.:
//někde předtím zavolám tuto metodu s parametrem třeba 0 - rekurze(0);
public int rekurze(int a){
if(a < 3){
a++;
rekurze(a);
}else{
System.out.println("tato větev je ukončena");
}
}
Tento kód si lze špatně představit a rekurzi vůbec. Nejvíce se rekurze používá pro prohledávání adresářů - to je asi ten nejlepší příklad. Prostě jde furt a furt do hloubky. Kdysi dávno jsem průběh rekurze od začátku až po konec tady kdesi popisoval -zkusím to najít. a pak přiložím. Je to hodně o představivosti, ale já to tu i zakreslil:) tak to zkopčím a hodím sem.
Do prdele.... zase spam jak kráva.... já už jen čekám, kdy mi dají banána-.-
Lubor Pešek:24.9.2016 0:13
to v dalším vlákně:D:D:D ale až teď je konečně chápu - díky tomu kolegovi, kterého jsem zmiňoval - on je fakt neuvěřitelný. Nepřemýšlí, prostě se usměje a radí stylem: vymaž tyhle kokotiny, napiš tenhle jednoduchý command (pochopitelně spletitý řetězec jak kráva ) a funguje to:D
no to mi ho fakt vyndej:) já tu rekurzi zkutečně našel:) Miluju linux!!! proklikávat to v oknech, to by mě jeblo:D takže tady je ta třída i s popisem - snad je to pochopitable:)
public class Rekurze {
private final Pismeno k = new Pismeno("k", null, null);
private final Pismeno j = new Pismeno("j", null, null);
private final Pismeno i = new Pismeno("i", null, null);
private final Pismeno h = new Pismeno("h", null, null);
private final Pismeno g = new Pismeno("g", null, null);
private final Pismeno f = new Pismeno("f", null, k);
private final Pismeno e = new Pismeno("e", i, j);
private final Pismeno d = new Pismeno("d", h, null);
private final Pismeno c = new Pismeno("c", f, g);
private final Pismeno b = new Pismeno("b", d, e);
private final Pismeno a = new Pismeno("a", b, c);
public Rekurze() {
rekurze(a);
}
public static void main(String[] args) {
new Rekurze();
}
private void rekurze(Pismeno p) {
if (p != null) {
System.out.println(p.toString().toUpperCase());
System.out.println(" 1:" + p.getA());
System.out.println(" 2:" + p.getB());
rekurze(p.getA());
System.out.println("*******");
rekurze(p.getB());
}
}
}
/**Postup
* Půjde nám o takovýto strom:
* H - I J - K - - H = potomek D a I,J = potomci E a G nemá žádné potomky
* \ / \ / \ / \ /
* D E F G D,E = potomci B a F,G = potomci C
* \ / \ /
* \ / \ /
* B C B,C = potomci A
* \ /
* \ /
* \ /
* \ /
* A A = Hlavní předek
*
* Nejdřív zadáme do rekurze Pismeno A (tím myslím instanci třídy Pismeno, ne skutečné písmeno)
* Proběhne první rekurze (rekurze Áčka):
* A není null, takže podmínka platí a spustí se první řádek, který dělá novou rekurzi - rekurzi Pismene B:
* B není null, takže podmínka platí a spustí se první řádek, který dělá novou rekurzi - rekurzi Pismene D:
* D není null, takže podmínka platí a spustí se první řádek, který dělá novou rekurzi - rekurzi Pismene H:
* H není null, takže podmínka platí a spustí se první řádek, který dělá novou rekurzi - rekurzi prvního null:
* null je null, takže podmínka neprojde a žádná rekurze nevznikne. Toto je první větev rekurze H, takže se pokračuje dál ve druhé větvi
* druhá větev H je null
* null je null, takže podmínka neprojde a žádná rekurze nevznikne. Toto je druhá větev rekurze H, takže Háčko končí
* druhá větev D je null
* null je null, takže podmínka neprojde a žádná rekurze nevznikne. Toto je druhá větev rekurze D, takže Déčko končí
* druhá větev B je E
* E není null, takže podmínka platí a spustí se první řádek, který dělá novou rekurzi - rekurzi Pismene I:
* I není null, takže podmínka platí a spustí se první řádek, který dělá novou rekurzi - rekurzi prvního null:
* null je null, takže podmínka neprojde a žádná rekurze nevznikne. Toto je první větev rekurze I, takže se pokračuje dál ve druhé větvi
* druhá větev I je null
* null je null, takže podmínka neprojde a žádná rekurze nevznikne. Toto je druhá větev řekurze I, takže Íčko končí
* Druhá větev E je J
* J není null, takže podmínka platí a spustí se první řádek, který dělá novou rekurzi - rekurzi prvního null:
* null je null, takže podmínka neprojde a žádná rekurze nevznikne. Toto je první větev rekurze J, takže se pokračuje dál ve druhé větvi
* druhá větev J je null
* null je null, takže podmínka neprojde a žádná rekurze nevznikne. Toto je druhá větev řekurze J, takže Jéčko končí
* Jelikož E už třetí větev nemá, tak končí i Éčko
* Jelikož B už třetí větev nemá, tak končí i Béčko
* druhá větev A je C
* C není null, takže podmínka platí a spustí se první řádek, který dělá novou rekurzi - rekurzi Pismene F:
* F není null, takže podmínka platí a spustí se první řádek, který dělá novou rekurzi - rekurzi prvního null:
* null je null, takže podmínka neprojde a žádná rekurze nevznikne. Toto je první větev rekurze F, takže se pokračuje dál ve druhé větvi
* druhá větev F je K
* K není null, takže podmínka platí a spustí se první řádek, který dělá novou rekurzi - rekurzi prvního null:
* null je null, takže podmínka neprojde a žádná rekurze nevznikne. Toto je první větev rekurze K, takže se pokračuje dál ve druhé větvi
* druhá větev K je null
* null je null, takže podmínka neprojde a žádná rekurze nevznikne. Toto je druhá větev řekurze K, takže Jéčko končí
* Jelikož F už třetí větev nemá, tak končí i eFko
* druhá větev C je G
* G není null, takže podmínka platí a spustí se první řádek, který dělá novou rekurzi - rekurzi prvního null:
* null je null, takže podmínka neprojde a žádná rekurze nevznikne. Toto je první větev rekurze G, takže se pokračuje dál ve druhé větvi
* druhá větev G je null
* null je null, takže podmínka neprojde a žádná rekurze nevznikne. Toto je druhá větev řekurze G, takže Géčko končí
* Jelikož C už třetí větev nemá, tak končí i Céčko
* Jelikož A už třetí větev nemá, tak končí i Áčko
*
* Když půjdete řádek po řádku a zakreslovat si správně vazby, měl by vám vyjít tento obrázek:
*
* null null null null null null null null
* \ / \ / \ / \ /
* \ / \ / \ / \ /
* \ / \ / \ / \ /
* H null I J null K null null
* \ / \ / \ / \ /
* \ / \ / \ / \ /
* \ / \ / \ / \ /
* \ / \ / \ / \ /
* D E F G
* \ / \ /
* \ / \ /
* \ / \ /
* \ / \ /
* \ / \ /
* \ / \ /
* \ / \ /
* \ / \ /
* B C
* \ /
* \ /
* \ /
* \ /
* \ /
* \ /
* \ /
* \ /
* \ /
* \ /
* \ /
* \ /
* \ /
* \ /
* \ /
* \ /
* \ /
* \ /
* A
*/
Tak jak psal výše Luboš Běhounek Satik udělal bych si normální pole pro hodnoty na které to budeš chtít rozměnovat. Pro jednoduchost těmto hodnotám budu dál říkat bankovky.
private final int[] bankovky = {1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000};
Následně bych postupoval jednoduchou metodou - našel bych si jakou nejvyšší bankovku budu potřebovat, a od té nejvyšší bankovky bych postupoval směrem dolů, vždycky bych spočetl kolik daných bankovek budu potřebovat, a kolik mi pak zbyde peněz. Výsledek bych průbežně ukládal do Mapy. Tady je metoda, která bere jako parametr částku kterou chceš rozměnit a vrací tu Mapu:
public Map<Integer, Integer> rozmen(Integer hotovost) {
Map<Integer, Integer> result = new TreeMap<>(); //sem se bude ukládat výsledek
//nejprve zjistíme jakou nejvyšší bankovku budeme potřebovat
int nejvyssi = 0;
for (int i = 0; i < bankovky.length; i++) { //procházíme pole hodnot bankovek
if (hotovost >= bankovky[i]) {
nejvyssi = i; //když je hotovost větší než hodnota bankovky uložena v poli pod indexem i, uložíme i do 'nejvyssi' a pokračujeme s dalším prvkem
} else {
break;
//vyskočíme z cyklu v okamžiku, kdy je hotovost menší než hodnota bankovky s indexem i, takže v 'nejvyssi' zůstane uložen index hodnoty
//nejvyšší bankovky, kterou budeme potřebovat
}
}
//a nyní samotné rozměnění
for (int i = nejvyssi; i >= 0; i--) { //procházíme pole od prvku s hodnotou nejvyšší potřebné bankovy dolů
int pocet = hotovost / bankovky[i]; //do poctu ulozime kolik bankovek dané hodnoty budeme potřebovat
hotovost = hotovost % bankovky[i]; //kolik hotovosti zbyde po odečtení použitých bankovek
if (pocet > 0) { //pocet 0 znamená, že při rozměňování není potřeba hodnota této bankovky
result.put(bankovky[i], pocet); //do připravené mapy si uložíme hodnotu bankovky jako klíč a počet těch bankovek jako hodnotu
}
}
return result;
}
Pole bankovky i metodu rozmen si dej do té třídy Rozmenovacka a pak to můžeš použít v metodě main třeba takto:
Scanner vstup = new Scanner(System.in);
System.out.print("Zadejte vasi hotovost :");
int castka = vstup.nextInt();
System.out.println("");
Rozmenovacka rozmenovacka = new Rozmenovacka();
rozmenovacka.rozmen(castka).entrySet().stream().forEach((entry) -> {
System.out.println(entry.getKey() + ":" + entry.getValue() + "x");
});
Zobrazeno 17 zpráv z 17.