#4 Flowy
Ale nenapisal, ze zacina, alebo sa uci ako sa pouziva pole. Co ak vie, ako sa pouziva pole. Mozno hlada len riesenie tohto problemu, lebo sa s nim este nestretol. Pytal sa ako sa zapisuje mnozina a ako sa zistuje ci dany element patri do mnoziny. Na obe otazky som mu odpovedal + navod ako to ma urobit, aby to porovnavalo cislo a farbu a nie referencie. Cize nemyslim si, ze to bol sarkazmus. Ked bude velmi chciet moze si urobit vlastnu implementaciu Set-u. Napriklad tak, ze urobi to pole a za kazdym ho prebehne a porovna vsetky elementy metodou equals(Object o).
Příspěvky odeslané z IP adresy 158.195.196.–
Pouzi Set a v class-e prepis overridni hashcode() a equals().
class RouleteNumber {
// len v pripade ze RouleteNumber je immutable
// ak sa objekt da menit tak len vypocitas result a
// vratis hodnotu
private volatile int hashCode
private int number;
private Color color;
public RouleteNumber(int number, Colot color) {
this.number = number;
this.color = color;
}
public int getNumber() {
return this.number;
}
public Color getColot() {
return this.color;
}
@Override
// vypocita sa hash cislo, ktore identifikuje dany objekt
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = 17;
result = 31 * result + number;
result = 31 * result + (color != null? color.hashCode(): 0);
hashCode = result;
}
return hashCode;
}
@Override
// metodu equals potrebujes ak dva objekty maju rovnaky hash
// v tom pripade sa vola equals a porovnavaju sa ich fieldy
public boolean equals(Object o) {
return o.getClass().equals(RouleteNumber.class) &&
((RouleteNumber) o).number == number &&
((RouleteNumber) o).color.equals(color);
}
}
// potom uz len niekde v kode staci
Set<RouleteNumber> setOfNumbers = new HashSet<RouleteNumber>();
// a mas cislo napr. r
setOfNumbers.contains(r); // toto vrati boolean
// K otazke
Set<RouleteNumber> setOfRedNumbers = new HashSet<RouleteNumber>();
setOfRedNumbers.contains(r); // vrati boolean ak sa tam nachadza
HashSet funguje so zlozitostou O(1). Lebo mas obrovsky array objektou. Vypocita sa hash a pomocou neho sa vypocita pozicia v poli. Ak viacero roznich objektov (equals dava false) ma rovnaky hash, tak sa vytvori linkedlist na danej pozici tychto objektov. Vyhoda je rychlost a to ze objekty nemusia byt z dobre usporiadanej mnoziny ako pre treeset (progrmatorsky: nemusia implementovat Comparable).
Precitaj si nieco o dialogovych oknach JDialog. Na tlacitko das ActionListener, ktory ti to okno vytvori a zobrazi.
#10 Kit
To je uplna pravda, ale podla mna zalezi dost od situacie. Skusme si predstavit taky priklad, ze budeme vytvarat noveho uzivatela a zapisovat do db.
class User{
private String username;
private String password;
// gettery a settery
}
interface UICreateUser {
public String askUserForName();
public String askUserForPassword();
// atd ...
}
class UserManager {
private UICreateUser ui;
// DI UICreateUser
public CreateUser(UICreateUser ui) {
this.ui = ui;
}
public User createNewUserFromUI() {
User user = new User();
Storage<User> storage = new Storage<>(User);
try {
// vynimku mozes hodit aj ked uzivatel pouzije
// nepovolene znaky
user.setUsername(ui.askUserForName());
user.setPassword(ui.askUserForPassword());
// ak to niekde hodi vynimku, tak sa to po commit nedostane
storage.commit(); // som si z casti prebehol ako
// funguje hibernate.
} catch (InvalidArgumentException e) {
// log invalid ako INFO
// je dobre mat aspon nejaku evidenciu
// ze nieco bolo zle zadane
}
}
}
Je omnoho pohodlnejsie, ako este riesit ci klikol na cancel, alebo nie. Aj ked uznavam Cancel je normalna reakcia, ale stale je to invalid argument. Dalo by sa to pre pokoj v dusi vyriesit takto:
private Pattern validUsernamePattern = Pattern.compile("\\w+");
public String getNameFromInputDialog() {
String name = JOptionPanel.createInputDialog(this, "Zadajte meno");
if (name == null)
name = "";
// da sa este vyuzit regex aby sa predislo
// nevhodnym uzivatelskym menam
// vyluci sa aj moznost toho, ze je to prazdny String
if (vaildUsernamePattern.matcher(name).matches())
throw new InvalidArgumentException("Invalid username");
return name;
}
Mozno je to mojou slabou predstavivostou, ale ina moznost ako odoslat referenciu na UserManager, ktory by obsahoval metodu cancel, alebo nieco poobne, ma nenapada. A ak by bola honota null, tak by volal cancel().
#6 Flowy
Informacie? Toto je vynimocna situacia, ked uzivatel stlaci Cancel. Cize odcakavas, ze to hodi vynimku. Program caka String, ale pravda ono to niekde hodi NullPointerException. Osetrujes to az na mieste, kde ten String naozaj potrebujes.
Tu je omnoho lepsie hodit vynimku. A spracovavat ju tam kde volas tuto metodu. Si predstav, ze budes mat nejaku default hodnotu, ktoru odosle ked stlaci uzivatel cancel. Spracovanie vynimky urobis nejak takto:
String name = null;
try {
name = frame.getNameFromInputDialog();
} catch(InvalidArgumentExecption e) {
e.printStackTrace();
// log e
System.exit(1);
}
// nieco vykonas s name
Da sa to aj bez vynimiek, casom pochopis preco to je horsie. Predpokladam ze ti to dava null a ten nevies metodou equals porovnat s prazdnym stringom.
if (meno == null || meno.equals("")) {
meno = "Jozef"; // Alebo
// System.exit(1);
}
return meno;
Co je abs a parameter z?
Navyse static ti nikdy nepojde, ak nie je static aj "pole".
A ten subor ma len jeden riadok?
A existuje ten subor s meno "file"?
Skus taketo nieco:
public String getNameFromInputDialog() {
String name;
name = JOptionPanel.showInputDialog(this, "Zadaj meno");
// Tu mozes vyuzit aj regex
if (name == null || name.equals(""))
// tu to spracujes alebo hodis vynimku a zachytis ju niekde inde
// ja tu hodim vyniku
throw new InvalidArgumentException("Invalid name");
}
A kde bude treba tam to odchytis.
Arrays mat metodu toString(/*pole*/), namiesto toho printArray().
Vsak si vytvor novy projekt. Do neho urob triedu BubleSort, ktora bude obsahovat jednu staticku metodu (nic viac zrejme nie je treba, teda aspon to nie je napisane v zadani). Asi takto by mohla vyzerat trieda:
class BubleSort {
public static int[] sort(int[] input) {
// sem napises kod bublinkoveho triedenia
}
}
A vytvoris triedu TestBubleSort. Neviem ci mozte pouzivat UnitTesy, tu je link ako sa to puziva: http://kar.kent.ac.uk/14122/1/Unit_Testing_in_BlueJ.pdf. BlueJ som v zivot nepouzil. A teraz som si vsimol, ze to mate akurat vypisat.
class TestBubleSort {
public static void main(String[] args) {
// Class generujui nahodne cisla
Random r = new Random();
int[] input = new int[50];
for(int i=0; i<50; i++) {
input[i] = r.nextInt(500)+1; // generuje nahodne cisla od 0-499
// preto + 1
}
System.out.println(printArray(input));
int[] sorted = BoubleSort.sort(input);
System.out.println(printArray(sorted));
}
public static String printArray(int[] array) {
// Class ktory si drzi pole characterov a potom z neho
// vytovri string, pomocou toString(). Lebo String je immutable
StringBuilde sb = new StringBuilder("[");
for(int i=0; i< array.length; i++) {
sb.append(array[i]);
// za poslednym prvkom pola nepises ciarku
if (i != array.length-1) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
}
Osobne by som testoval radsej pomoou UnitTest-ov. Kod nie je kompletny, je to iba navod ako by som postupoval.
Neviem ci nie je problem v tom ze sa snazis nieco nacitat a zaroven zapisat do toho isteho suboru. Ak je to len ~1000 riadkov, skus to nacitat cele upravit a potom naraz zapisat. Este ma napada skus pouzit metodu flush(), ma ju kazdy stream.
A chyba mi tam v settery void, ten python.
Aj ked mas tu 5 riadkov, z ktorych toho nevycitam viac ako si popisal slovne.
tak ze vytvoris synchronizovane settery a gettery.
class ObjectWithArray{
private int[] array;
public ObjectWithArray(int[] array) {
this.array = new int[array.length];
System.arraycopy(array, 0, this.array, 0, array.length);
}
public synchronized int getElement(int idx) {
// if idx not in array throw exception
return this.array[idx];
}
public synchronized setElement(int idx, int element) {
// if idx not in array throw exception
this.array[idx] = element;
}
}
actionPerformed nemusi byt synchronized dolezite je aby get a set bol.
Preco to neulozis aj s celym polom, pole je serializovatelne. Potom ho nacitas.
Velmi sa ospravedlnujem som debil :D. Som si updatol databazu, ale stale som mal referenciu na povodny objekt s neupdate-nutimi poliami. Uz mi to bezi.
Array chcem preto ze dana vec sa ma spravat ako array stringov a nic viac, cize nechcem dalsi model.
Dakujem za inofmacie, z casti mi pomohli. Metody som presunul do extendnuteho FilterQuerySet-u, aby som ich mohol pouzivat s metodami QuerySet-u. Funguje to ked pole zadam pri vytvoreni modelu. Ale stale nefunguje update tam mi to pri testoch vzdy failne, ako keby sa nove hodnoty v poli vobec nezmenili.
skusal som to dvomi sposobmi oba zlihali:
class FilterQuerySet(models.query.QuerySet):
def add_rules(self, array, tags=[]):
# check toho ci su hodnoty spravne
tags = set(tags)
for flt in self.all():
flt_tags = set(getattr(flt, array))
new_tags = list(flt_rules | tags)
kwargs = {array: new_tags,}
self.filter(pk=flt.pk).update(**kwargs)
# a podobne aj
def add_rules(self, array, tags=[]):
#check
tags = set(tags)
for flt in self.all()
flt_tags = set(getattr(flt, array))
new_tags = list(flt_rules | tags)
setattr(flt, array, new_tags)
flt.save()
v oboch pripadoch rovnaky vysledok testu ktory mal pridat pole: ['foo', 'bar', 'baz'] !=[].
Ale ak som Filter vytvoril s timito poliami tak tam boli, taktiez testovane.
Toto nie je ten najlepsi sposob riesenia danho problemu. Ak chces robit animaciu, tak overridnes paint alebo paintComponent. Vhodne je si vytvorit Drawable object, ktory si drzi vstky potrebne veci a vie sa vykreslit, ked o to poziadas, prip. updatnut. Ja by som siel asi nejako takto, ale vobec sa toho nemusis drzat. Pozor ten kod nieje kompletny treba ho dopisat, aby fungoval.
interface Drawable extends Observer{
public void draw(Graphics g);
}
class Canvas extends JPanel implements Observer{
private final List<Drawable> drawableObjects = new ArrayList<>();
public List<Drawable> getDrawable() {
return this.drawableObjects;
}
// metody
@Override
public void paintComponent(Graphics g){
super.paintComponent(g); // prekresli na krasnu sedu
// tymto docielis aby ti ostatne kruhy zmizly
for (drawableObject : drawableObjects) {
drawableObject.draw(g);
}
}
@Override
public void update(/*Tu neviem ake su argumenty ale java doc a slusne IDE ti prezradia*/){
repaint(); // toto by mohlo stacit na update
// vola funkciu update(Graphics g) a ta pain a
// paintComponent
}
}
class Animation{
// Toto je v nejakej class-e napr. nazvyme je Animation
// a observable moze byt jeho field. A budes mat aj lepsi pristup k nemu
private final Observable observable = new Observale();
public Observable getObservable() {
return this.observable;
}
public void runAnimation() {
int delay = 1000; //milliseconds
// toto nemusi byt len lokalna premenna moze to byt v classe co sa stara o
// animaciu
// das tam vsetky observery a spustis
ActionListener taskPerformer = new ActionListener() {
Observable obs = observable
public void actionPerformed(ActionEvent evt) {
obs.notifyObservers()
}
};
new Timer(delay, taskPerformer).start();
}
}
class DrawableCircle implements Drawable{
int x,y; //cez kostruktor nastavis
int w,h;
@Override
public void draw(Graphics g){
g.drawOval(x,y,w,h);
}
@Override
public void update(/*znova tie iste fieldy*/) {
this.w++;
this.h++;
}
}
Tu je Timer: http://docs.oracle.com/javase/7/docs/api/javax/swing/Timer.html a tu je nieco napisane o Observable a Observery: http://www.javaworld.com/article/2077258/learn-java/observer-and-observable.html.
Inak v tvojom rieseni staci dopisat do toho for cyklu super.paintComponent(g); na zaciatok a pojde to. Ale odporucam ti pouvazovat aj nad tym postupom co som napisal, kvoli lepsej modularite. A mozno ti to bude tearovat, take veci sa odstranuju double buffeingom. V podstate renderujes do obrazku (backbufferu) a potom ho vykreslis naraz na obrazovku.
Vsak, ked niekto vyplni cast formulara, tak predpokladam, ze mas nikede zaznacene, kto ho vyplnil. Takze ked ten dany uzivatel pride znova, tak mu SELECT-nes jeho riadok vratis do formulara. A vo formulary to spracujes. A ked to uzivatel odosle, tak len checknes ci je vsteko vyplnene. Pripadne si mozes viest niekde, co je este nevyplnene a kolko. Ci takto to nema fungovat?
Dobry den,
chcel by som sa opytat ci ste niekto neriesili, pripadne neviete ako vyriesit problem s vkladanim elementov do PostgreSQL pola. Som si troska cital o PostgreSQL a zapacilo sa mi zopar ficur, ktore ponuka. Ale mam velky problem s vlozenim elementu do pola v databaze. Mohol by som to riesit aj inymi sposobmi, ale na co ked je tam datovy typ pola. Skusal som aj projekty djorm_pgarray aj dbarray, ale neuspesne. Tak ze sa to teraz snazim vkladat rucne.
Teraz to skusam, tak som si vytvoril model Filter, ktory drzi pole tagov a mam Message, ktory obsahuje taktiez list tagov. Ked sa niektore tagy zhoduju, tak od toho odcakavam ze mi to vrati True v opacnom pripade False.
Nechce sa mi tu davat cely kod, ale dam sem aspon tu cast o ktorej si myslim, ze je dolezita:
class Message:
tags = list() # list tagov tie sa pridavaju pri inicializacii a su kontrolovane
# tu chyba nebude tento objekt zbehol testami
# dalsie fieldy a metody
# messages/models.py
from djorm_pgarray.fields import ArrayField
from django.db impot models, connection
class Filter(models.Model):
# fieldy
tags = ArrayField(dbtype='char(32)')
def add_tag(self, element):
sql = """UPDATE %s SET %s = array_append(%s, '%s') WHERE id=%s;"""
sql = sql % (self._meta.db_table, 'tags', 'tags', element, self.id)
cursor = connection.cursor()
cursor.execute(sql)
# ked som tuto metodu testoval a dal som si vytiahnut pole
# pomocou napr. SELECT tags FROM messages_filter WHERE id=1
# cez cursor.execute(sql) a cursor.fetchone() tak som dostal prvy tag
# a test zbehol.
# dalsie metody
def overlap(self, message):
# v skutocnosti mam na toto vytvoreny builder, aby som mohol
# vyuzivat troska viac veci. Ale bol testovany v nom by problem byt
# nemal.
sql = """SELECT (SELECT %s FROM %s WHERE id=%s) && %s"""
sql = sql % (
'tags',
self._meta.db_table,
self.id,
PostgresArrayBuilder(message.tags, 'char(32)').as_psql_array()
)
# PostgressArrayBuilder v podstate urobi z hocicoho iterovatelneho
# ARRAY a overy ze su v tom iterovatelnom objekte spravne parametre.
# ['tag1', 'tag2', 'tag3'] -> "ARRAY['tag1', 'tag2', 'tag3']::char(32)"
cursor = connection.cursor()
cursor.exceute(sql)
return cursor.fetchone()[0] # a tu mi to za kazdym vrati null
# a tym padom mi test pre tuto metodu
# failol.
S postgresql som len zacal robit, tak ze este velmi neviem v com moze byt problem. Ale ked som si dane prikazy skusal len tak v db tak to fungovalo. Moze byt nejaky problem s django.db.connection-om? Engine mam v settingsoch nastaveny na: 'django.db.backends.postgresql_psycopg2'. Vela som googlil a to co som nasiel mi velmi nepomohlo. Ak budete mat niekto nejake navrhy, prip. viete kde robim chybu, tak vam voperd dakujem za vasu odpoved.
Lebo si nevytvoril referenciu na stroj. Cize cely kod by mohol vyzerat nejak takto.
class DatabazaStrojov {
Map<Integer, Stroj> stroje = new HashMap<>(); // <> operator je len v jave 7 a
// vissie. V < 7 musis pisat
// new HashMap<Integer, Stroj>()
// Ak ma kazdy stroj definovane svoje ID
public void pridajStroj(Stroj s) {
stroje.put(s.getID, s);
}
// Ak nema definovane svoje id v objekte stroj
public void pridajStroj(Integer idStroja, Stroj s) {
stroje.put(idStroja, s);
}
// Touto metodou budes vediet vytiahnut stroj podla jeho id
public Stroj vratStroj(Integer id) {
return stroje.get(id);
}
// Atd. ...
}
class Stroj {
// tu mas nejaky kod
}
// a budes s tym pracovat nasledovne
DatabazaStrojov d = new DatabazaStrojov();
// ak mas v stroji definovane id
d.pridajStroj(new Stroj(12345));
d.pridajStroj(new Stroj(12325));
// atd
// ak nemas v stroji definovane jeho id
d.pridajStroj(12345, new Stroj(/* premenne */)));
// a vytiahnes data nasledovne
Stroj strojSId12345 = d.vratStroj(12345);
Vyssie bolo napisane len ako sa to pouziva. Toto co som napisal ja je v podstate wrapper nad HashMapou.