Java 8 vs Scala Lambdat bytecode tasolle

Java 8 julkaistiin pitkän odottelun jälkeen, ja viimein kieleen saatiin Lambda lausekkeet – sekä niitä hyödyntäviä rajapintoja aikaiseksi. Monessa muussa kielessä Lambdat ovat olleet jo pitkään, ja voidaan ehkä sanoa että Scala popularisoi ne. Jäin miettimään onko Java ja Scala lambdatoteutuksissa eroja bytecodetasolla, molemmat kun ovat käännettäviä kieliä. Törmäsin kiintoisaan artikkeliin:

 

http://www.takipiblog.com/2014/01/16/compiling-lambda-expressions-scala-vs-java-8/

 

Aikanaan kun Scala tehtiin, kieleen lisättiin monenlaisia rakenteita jotka toteutetaan aika rajulla bytecode teurastuksella. Esim. funktio ilman luokkaa ei ole Javassa ollut mahdollinen, joten Scalassa on luotu keinotekoisia luokkia jos johonkin väliin. Lopputulos on kielen osalta hieno ja innovatiivinen mutta bytecode tasolla vähän purkkaviritystä.

Java 8 toteuttaa Lambdat käyttäen Java 7:ssä lisättyä uutta bytecode tason piirrettä nimeltä invokevirtual. Näin vältetään purkkaviritykset väliin, ja funktio voidaan luoda sellaisenaan. Syntyvä bytecode on paljon mutkattomampaa. Suorituskyvystä ei artikkelissa puhuttu mutta voisin arvata että senkin suhteen Java 8 vetää pisteet kotiin.

Eli koska rakastan kovasti Scala kielellä koodailua – se tuntuu raikkaan keväiseltä hengähdykseltä – tässä toivelista Scala piirteille joita pitäisi ottaa kiinni:

– Sama optimointi: Käytetään Java 7 invokedynamic piirteitä

– Samantien voitaisiin toteuttaa vähäisemmät Java 7 Coin piirteet: binääriliteraalit, try-with-resources (AutoCloseable), alaviivat numeroiden ryhmittämiseen (tämä ei ehkä onnistu ollenkaan koska villikortti), jne.

Mainokset

Ohjelmointikielten suosituimmuudesta

Aika ajoin aina tulee vastaan kysymyksiä siitä mikä kieli on nyt kova, onko joku laskussa? Onko jotain uutta tulossa? Mitä pitäisi opiskella ollakseen kilpailukykyinen työmarkkinoilla?

Vaikeahan näihin on vastata, riippuu pitkälti näkökulmasta. Aiemmin olen seuraillut Tiobe indeksiä, mutta siinäkin systeemissä laskutapa herättää vähän mietintää.. Siinä käytetään referenssinä hakukoneiden tietoja, eli se listaa kieliä sen mukaan mitä hakukoneet löytävät. Organisaatioiden sisäisistä hankkeistahan ei paljoa välttämättä ulospäin näy. Mutta on se silti suuntaa antavaa. Tioben kärjessä on kimallellut Java pitkään, tosin hiukan aikaa sitten C kieli pomppasi yllättäen sen ohi. Ja kyse ei siis ole ObjectiveC suosiosta, se näkyy omana trendinään matalalla. Mutta Javan osuus on 18% paikkeilla, joka jättää toki runsaasti tilaa muille. Tätä kirjoittaessa Tioben viisi kovinta ovat:

  •  Java (18.4%)
  •  C (17.1%)
  •  Objective C (reipas nousu, 9.8%)
  •  C++ (8.8%)
  •  C# (6.7%)

Näitä seuraa PHP, Python, ja Visual Basic, jonka jälkeen aletaan puhumaan jo alle kahden prosentin osuuksista. Yllättävästi esim. Ruby, JavaScript, menevät tänne kategoriaan, saaden seuraa kielistä kuten Lisp, Pascal, Assembler 😉 Josta syystä kyseenalaistankin vähän tuloksia. Olisiko kuitenkin niin että esim. AJAX:ia ja JavaScriptiä käytellään paljon enemmän nykyään, mutta sitä ei pidetä koodaamisena koska se on yleensä jonkun muun projektin sivutuote ja saattaa perustua valmiskirjastojen käyttöön?

Joka tapauksessa, aamulla lukiessani uutisia törmäsin toiseenkin aika kiintoisaan indeksiin. Kyseessä on RedMonk indeksi, jossa laitetaan ohjelmointikielet järjestykseen matriisiin kahden kriteerin perusteella: miten usein kielen nimi esiintyy StackOverFlow keskusteluissa, ja miten moni GitHub projekti käyttää ko kieltä. RedMonk top kielet näin verraten ovat:

  • JavaScript
  • Java
  • PHP
  • Python
  • Ruby
  • C#
  • C++
  • C
  • Objective-C
  • Shell

Eli nämä kaksi eri laskutapaa näyttävät olevan osittain ristiriidassa. Java löytyy kunkkuna molemmista, mutta juurikin JavaScript, Ruby tuovat suorastaan päinvastaiset näkemykset. Itselleni tämä lista vaikuttaa uskottavammalta. Tässä myös kiinnostavaa että omat seurannan alla olevat lempikielet Scala ja Groovy ovat kovassa nosteessa, ja kirivät jo kiinni kärkipään kieliä. Tosin niiden kanssa samoissa lukemissa on myös Assembler, Matlab, ja vastaavat 😉

language-ranking-0912

Joka tapauksessa, yhdistellen noita molempia listoja niin tuskin menevät investoinnit hukkaan jos panostaa osaamiseen sektoreilla Java, C#, C, C++, ObjectiveC. Kiistanalaisempia mutta kiinnostavia ovat PHP, Python, JavaScript, Ruby. Tietysti on myös hyvä seurata rakettimaisessa nousussa olevia kieliä, molemmat indeksit listaavat omat nousijansa. Tioben kovia nousijoita ovat ObjectiveC, Java (joku tilapäinen pomppu), Python. RedMonk listailee mm. nousijoiksi CoffeeScript, Visual Basic, ASP, Assembly, C++, Haskell, Scala.

Mielenkiintoista myös se näkyvätkö/miten näkyvät mobiiliteknologiat näissä. ObjectiveC viittaa selvästi iLaitteiden suuntaan, kun taas Android osunee Java massan alle. Omaan tutkaan on osunut yhä enemmän mobiiliprojekteja koto-Suomessakin.

Eli onko uutta Javantappaja-kieltä joka muuttaisi Javan uudeksi Coboliksi? Eipä näy vielä tutkassa. Ehkä sellaista ei tulekaan. Ehkä me elämme Polyglot aikaa, ja on vain oltava useita kieliä työkalupakissa. Toisaalta suosituimmat kielet listalla ovat jo aika vanhoja, niiden on aika elää ajan mukana ja muuttua, tai jähmettyä kiveksi ja jäädä jalkoihin. Onnistuuko tuleva Java 8 tässä? Entäpä HTML5+JavaScript?

 

 

Tuossapa linkkejä tuloksiin ja meidän kursseihimme alueilta (ObjectiveC ja iphone ohjelmointi tulossa pian):

http://redmonk.com/sogrady/2012/09/12/language-rankings-9-12/

http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html

http://www.tieturi.fi/kurssit/koulutus.html?category=Open+Source+Java

http://www.tieturi.fi/kurssit/koulutus.html?category=Web

http://www.tieturi.fi/kurssit/koulutus.html?category=Microsoft-teknologiat

http://www.tieturi.fi/kurssit/koulutus.html?category=Muut+ohjelmointiteknologiat

 

Scala of the day – RSS reader

Pidin juuri Scala kurssia ja taas tuli hurmaannuttua kielen yksinkertaisesta eleganssista tietyissä operaatioissa. Ensi vuonna jää nähtäväksi miten Java 8 Lambda Expressions vastaa tähän.

Mutta tässä yhden harjoitustehtävän hedelmä; koodi joka lukee Tieturin blogista kaikki otsikot ja listaa ne ruudulle:

  for ( line
       <- Source.fromURL("http://feeds.feedburner.com/tieturi").getLines
        if line contains("<title>") )
          println (line)

Ja tässä tämänhetkinen tulostus:

 <title>Tieturi</title>
  <title>Tieturi</title>
  <title>Työympäristö muuttuu yhä vaativammaksi, pysyykö työntekijä tahdissa mukana?</title>
  <title>Arvoista hyveisiin – päämääristä tuloksiin!</title>
  <title>Lean IT – onko palveluprosessissa läskiä?</title>
  <title>Maailmaa muuttamassa yhdessä Jurgen Appelon kanssa</title>
  <title>Kokonaisarkkitehtuuri on kaikkien asia – ei vain tietohallinnon!</title>
  <title>Tieturilaisten etäpäivästä ekopäivä</title>
  <title>HTML5 ja JavaScript – kahvipöydässä kuhisee</title>
  <title>Windows Phone 8 tähtää varteenotettavaksi yrityspuhelimeksi</title>
  <title>Pienennä hiirijalanjälkeäsi</title>
  <title>Tervetuloa IPv6!</title>

I likes it! 😉

Otetaanpas tuolta kommenttiosiosta vielä tiiviimpi ja scalamaisempi tapa tehdä sama:

Source.fromURL(“http://feeds.feedburner.com/tieturi”).getLines.filter(_.contains(“<title>”)).mkString(“\n”)

Effective Java == Scala?

Olen viime aikoina pyörinyt paljon Scala kielen parissa, kurssiamme päivitellen ja kieltä syvemmin opiskellen. Parhaillaan käynnissä olevassa JavaOne seminaarissa Scala tuntuu olevan edelleen nousussa oleva kiinnostava trendi, ja mm. Twitter, FourSquare, LinkedIn uskovat siihen. Edelleenkin kiinnostavaa on että opiskelemalla Scala toimintamallia oppii samalla vankan ymmärryksen siitä miten tulevan Java 8:n Lambda Expressions malli toimii, ja ennustan jo että siitä tulee VALTAISA juttu parin vuoden sisään.

No niin, törmäsin mielenkiintoiseen artikkeliin. Joshua Bloch niminen kaveri kirjoitti aikanaan kirjan Effective Java, josta on jo useampi painos otettu. Monet pitävät tätä alan perusteoksena joka kertoo miten Java kieltä tulee käyttää. Artikkelissa huomioidaan että kun otetaan pohjaksi Java, ja sovelletaan kirjan sääntöjä, saadaan Scala. Eli Scala == Effective Java. Olisiko aika opiskella uusi kieli? 😉

Minulla on ongelma. Olen huikean rakastunut sekä Grails, että Scala alustaan, puhumattakaan Androidista. Ja Javakin menee eteenpäin. Onko loppuelämäni polyglot pohjaista vai nouseeko vielä yksi ylitse muiden ? Stay tuned…

 

http://grahamhackingscala.blogspot.fi/2011/01/does-scala-equal-effective-java-bloch.html

 

Java, optimointi, ja muistivuodot

Hiljattain tuli konsultoinnin yhteydessä pohdiskeltua tarkemmin miten huonosti käyttäytyviä Java-sovelluksia tuunataan. Javassa alustanahan on pari erityispiirrettä jonka vuoksi se toimii eri tavalla kuin esim. C++.

– Koska Java on dynaaminen alusta, sen kokonaisympäristö selviää vasta ajon aikana, ja voi mahdollisesti poiketa kehitysympäristöstä. Tarkoittaa että esim. log4j kirjastosta voi olla eri tavoin toimiva kirjasto ajon aikana. Kenties näin ei pitäisi olla mutta näin useinkin on.

– Tehokkuudesta vastaa pääosin virtuaalikone, eli ajoympäristö, ja se onkin uskomattoman hyvä optimoimaan. Java koodi benchmarkattuna C++ koodia vastaan on viime aikoina useasti jopa rökittänyt kilpailijansa suoritusnopeudessa. Mutta virtuaalikone tekee parhaiten työntä koodille joka on selkeää ja kikkailematonta, vähän kuin rautalangasta väännettyä. Yksi pahimpia hölmöilyjä mitä voi tehdä on lisätä koodiinsa kutsu System.gc() sinne sun tänne. Virtuaalikoneen idea on nimenomaan skaalata sovellus ympäristön mukaan aina parhaiten optimoiduksi. Mitä enemmän koodi pyrkii pakottamaan ja rajoittamaan sitä huonommin automaattioptimointi voi toimia.

– Kooditasolla ei ole mitään erityisiä optimointi-avainsanoja kuten esim. inline.. Koodin optimoinnilla on muutenkin hyvin vähän merkitystä sujuvuuteen – kunhan siellä ei ole hölmöilty. Pääosa koodin optimointia on siis hölmöilyjen purkamista.

– Automaattinen roskankeruu on tunnettu tehosyöppö, edellämainityt hölmöilyt ovat usein koodia joka aiheuttaa tarpeetonta roskankeruuta. Tarpeeton roskankeruu syö prosessoritehoa ja pysäyttää suorittavat säikeet, eli mitä enemmän roskankeruuta tehdään sitä enemmän varastetaan kellosyklejä suorittavilta osilta. Näin ollen roskankeruun minimoiminen on hyvä lähtökohta suorituskyvyn parantamiselle. Mutta huom. tarpeettoman roskankeruun.

Suorituskykyä parannetaan siis roskankeruuta vähentämällä – tarpeetonta sellaista. Miten tämä tapahtuu? Pidentämällä olioiden elinkaarta ja lisäämällä uudelleenkäyttöä, välttämällä kaikkea turhaa olioiden luontia ja tuhoamista.  Tähän on monia keinoja: staattiset muuttujat ja alustusblokit, objektipoolit, cachet, valmiiksi lasketut tulokset, jne.

Muistivuotoja ei pitäisi Javassa periaatteessa olla – automaattisen roskankeruun ansiosta. Javassa kun ohjelmoija ei itse varaa muistia eikä vapauta muistia vaan nämä piirteet on abstraktoitu virtuaalikoneen tehtäviksi. Mutta virtuaalikoneessakin voi olla bugeja, ja missä hyvänsä JNI palikoissa voi olla ja todella usein onkin muistivuoto-ongelmia. Ja jos ohjelma yksinkertaisesti varaa olioita muistiin jatkuvasti eikä milloinkaan päästä niistä irti niin eipä roskankeruukaan voi toimia ja toki siinä muisti aikanaan sitten loppuu. Jos haluat saada java-sovelluksen kaatumaan muistiongelmaan et tarvi tätä enempää:

        List<String> list = new ArrayList();
        while(true)
            list.add("HELLOWORLD" + list.toString());

Tässä on IBM:n Developerworks-sivuilta hienostuneempi esimerkki joka esittää paria vivahdetta:

import java.io.IOException;
import java.util.HashSet;
import java.util.Random;
import java.util.Vector;

public class LeakExample {
	static Vector myVector = new Vector();
	static HashSet pendingRequests = new HashSet();

	public void slowlyLeakingVector(int iter, int count) {
		for (int i=0; i<iter; i++) {
			for (int n=0; n<count; n++) {
				myVector.add(Integer.toString(n+i));
			}
			for (int n=count-1; n>0; n--) {
				// Oops, it should be n>=0
				myVector.removeElementAt(n);
			}
		}
	}

	public void leakingRequestLog(int iter) {
		Random requestQueue = new Random();
		for (int i=0; i<iter; i++) {
			int newRequest = requestQueue.nextInt();
			pendingRequests.add(new Integer(newRequest));
			// processed request, but forgot to remove it
			// from pending requests
		}
	}

	public void noLeak(int size) {
		HashSet tmpStore = new HashSet();
		for (int i=0; i<size; ++i) {
			String leakingUnit = new String("Object: " + i);
			tmpStore.add(leakingUnit);
		}
		// Though highest memory allocation happens in this
		// function, but all these objects get garbage
		// collected at the end of this method, so no leak.
	}

	public static void main(String[] args) throws IOException {
		LeakExample javaLeaks = new LeakExample();
		for (int i=0; true; i++) {
			try { // sleep to slow down leaking process
				Thread.sleep(1000);
			} catch (InterruptedException e) { /* do nothing */ }
			System.out.println("Iteration: " + i);
			javaLeaks.slowlyLeakingVector(1000,10);
			javaLeaks.leakingRequestLog(5000);
			javaLeaks.noLeak(100000);
		}
	}
}

Miten tällaisia roskankeruuseen tai muistivuotoon liittyviä ongelmia sitten voi jahdata? Aika monellakin tapaa, Java tuo mukanaan jo useita työkaluja joiden avulla pääsee näkemään tarkemmin mitä virtuaalikoneen sisällä tapahtuu. Näistä on monesta kursseillakin asiaa, mutta viime aikoina olen perehtynyt enemmän visualvm työkaluun joka on jdk 6  uudemmissa versioissa sekä jdk 7:ssa vakiovarusteena. Sen saa ladatuksi myös erillisenä verkosta. VisualVM sisältää mahdollisuuden profiloida prosessorin käyttöä tai muistin käyttöä, ja sillä voi ottaa snapshotteja joita voi analysoida kaikessa rauhassa myöhemmin. Näin voi kiinnittää huomiota pisteisiin jossa käytetään paljon aikaa, tai jossa luodaan paljon olioita.

Miten em. muistivuoto sitten Javasta löytyy? Helposti. Otetaan snapshot tilanteesta, ja toinen snapshot jonkin aikaa myöhemmin. Muistivuodon tunnusmerkki ei ole että olio varaa paljon muistia. Muistivuodon tunnusmerkki on kasvu, josta kertoo kahden snapshotin delta, ero. Ja visualvm pystyy ottamaan kaksi snapshottia ja vertailemaan niitä, jolloin voidaan pistää oliot kasvun mukaan järjestykseen. Kovasti kasvava olio ei ole välttämättä signaali muistivuodosta, voi olla että se on vain kovasti kasvava olio 😉 Mutta jos ohjelmassa on muistivuoto, näiden joukosta se löytyy. Ellei se ole esim. virtuaalikoneen tai JNI moduulin bugi – koska nämä ovat java heapin ulkopuolella toimivia, ei niihin javan sisäiset välineet pure.

Yksi muistivuodoksi nimetty ongelma on se kun vastaanottaa ihastuttavan OutOfPermGenSpace -poikkeuksen. Tämä ei ole tosiasiassa varsinainen muistivuoto vaan ilmiö joka on joissain versioissa ilmentynyt mm. Tomcat ja JBOSS palvelimilla. Se aiheutuu kun serverille tehdään hot deploy operaatioita uudelleen ja uudelleen. Riippuen hot deploy toteutuksesta, java asentaessaan softan uuden version saattaa päätyä käyttämään enemmän ja enemmän permgen-aluetta kunnes se loppuu kesken. Tähän voi reagoida joko lisäämällä permgen alueen viipaletta (joka lykkää ongelman esiintymistä vähän pidemmälle), tai buuttaamalla serverin ihan oikeasti aika ajoin, esim. aina neljän hot deployn jälkeen, tai tarkistamalla että oma serveri tukee hot deployta ilman näitä oireita.

Yksi itseä kiehtova asia on rinnakkaisuuden jatkuva lisääntyminen. Omassa Xoom tabletissani on pari prosessoriydintä, samoin puhelimessani. Pöytäkoneissa on jo 2, 4, 8, ja pian 64 ydintä. Lisäboostia saa tekemällä asiat rinnakkain, silloin kun se on mahdollista, ja tähän tarvitaan tietysti osaamista jo suunnittelun alusta alkaen aina toteutustekniikoihin asti. Miten rinnakkaisessa maailmassa hallitaan jaettuja resursseja? Kiinnostavat projektit kuten Akka ja Scala vastaavat että Actor frameworkeillä ja postilaatikoilla. Java sanoo että synkronoinnilla ja lukituksilla. NIO tarjoaa sokettien osalta mukavan selector mallin jossa säikeitä tarvitaan vain kaksi, ja asiakkaita voi silti olla vaikka tuhat. Tässä ollaan vielä lastenkengissä, ja 2010 luku on rinnakkaisuuden vuosiluku, sanokaa minun sanoneen.

Tämä kirjoitelma syntyi Tehokas Java-kurssin tiimoilta, eli jos suorituskyvyn säätö Java-alustalla herättää kiinnostusta ja tässä artikkelissa tuli jotain uutta, niin kannattaa kurkata http://www.tieturi.fi/java alta ko kurssi esille.

JFokus 4/4 – Se oli siinä

Scalasta

JFokuksen toinen eli viimeinen päivä on nyt ohi ja viimeiseen asti riitti tiivistä asiaa. Toisen päivän kuningasteemana oli Scala. Scala ninjailu veti salin niin täyteen että osa joutui seisoskelemaan pitkin käytäviä. Hauska esitys toi tunnissa esille olennaiset piirteet hyvin tiiviissä paketissa, ja tuotiin myös esille sudenkuoppia ja pulmia joita aloittelija kohtaa. Suomessa ensimmäinen Scala kurssi on myös pidetty, ja jatko-osia tahkotaan syksylle. Itse pidän Scalaa hyvin raikkaana tuulena kuutisentoista vuotta Javaa tahkonneena. Onko Java uusi Cobol ja Scala uusi Java? Ehkäpä ei, mutta kokeile molempia ja muodosta oma mielipiteesi.

Scalan kehittäjä Martin Odersky piti myös esityksen kokoelmista, ja siinä sivussa Scalan ilmaisuvoimasta, ja antoi myös roadmappia mitä uusissa versioissa on tuloillaan. Kun ytimien määrä ja rinnakkaisuuden tarve alati kasvaa, tarvitaan perinteistä säieohjelmointia tehokkaampia malleja, nimenomaan ohjelmoijan kannalta. Scalan kokoelmissa on paljon funktionaalisia ominaisuuksia joita hyödyntämällä sovelluksen käyttöä voi helposti skaalata ylöspäin.

Scrum, Kanban ja ketterä suunnittelu

Scalan ohella päivä täyttyi sitten HTML 5:lla ja ketteryydellä. Olen jo aiemmin nähnyt mihin HTML5 pystyy joten se on kovin kiinnostava uusi suuntaus, mutta toisaalta ei kovin monimutkainen. HTML harrastajille siinä on paljon uutta, mutta ohjelmoijille taas aika suorasukaista tekniikkaa. HTML harrastajilla tarkoitan tässä niitä lukuisia jotka tietävät että b tekee lihavoinnin ja h1 on otsikko mutta eivät tiedä mitä span tekee tai miten tehdään toimiva lomake. Olen kursseilla nähnyt oppilaiden tekevän jo uskomattomia asioita HTML 5:lla, kun heillä on hetkinen aikaa käytössään, ja Google on myös kärkäs näyttämään erilaisia kikkoja. Aika hyvin tekniikalta jonka virallinen ensispesifikaatio on vamis 2014 😉

Mielenkiinto ketteryyteen oli melkoinen, lisää näkökulmia tekijöiltä ja käytännön kokemuksia. Neal Ford on erinomainen puhuja ja Emergent Design luennossa oli paljon ajatuksia siitä miten käytännössä voit suunnitella fiksusti. Eli ei etupainotteisesti, mutta ei myöskään unohtaen suunnittelu kokonaan. Esityksessä oli mm. testivetoisesta kehityksestä, mutta myös jälkikäteen refaktoroinnista ja teknisen velan merkityksestä. Itseen teki vaikutuksen välineet ja mittarit joilla voi perustella teknisen velan purkamista projektin tilaajapuolelle. Neal Ford mainitsi SOA:n esimerkkinä tarpeetoman monimutkaisesta antipatternista 😉

Henrik Knibergillä oli erinomainen esitys Scrum ja Kanban käytännöistä: Tarkasti ottaen 15 loistavaa vinkkiä. Mitään kovin ristiriitaista ei esitetty, vaan osa ideoista oli hyvinkin tuttuja, mutta muutama hyvin perusteltu juttu taas herätti mielenkiinnon: esim. älä laske tuntimääriä taskeille, ja tee automatisoidusta testauksesta oma backloginsa josta osia virtaa ajan myötä sprintteihin hyvin priorisoituna. Tämä oli käytännössä päivitys alan perusteokseen Scrum and XP from the trenches – ja osa asioista mitä tuossa kirjassa rummutettiin olikin nyt listalla asioita joita EI pidä tehdä. Näin muuttuu maailma neljässä vuodessa 😉

Eli päivä alkaa olla paketissa, ja alkaa matka takaisin Helsinkiin. Jälkimietteinä Java näyttäisi voivan vahvasti, ja niin koko IT ala. Innovaatio on taas vahvaa ja paljon tapahtuu. Aika palata sorvin ääreen ja alkaa käyttämään uusia asioita liikearvon tuottamiseen 😉

Tässäpä muutama linkkiresurssi reissua koskien:

http://www.infoq.com/minibooks/scrum-xp-from-the-trenches

http://en.wikipedia.org/wiki/Cyclomatic_complexity

http://javancss.codehaus.org/

http://www.jfokus.se/jfokus/

http://vaadin.com/home

Sekä tietysti:

http://www.tieturi.fi/java