Aleksander Radovan
Autor:
Aleksander Radovan

Voditelj Java tima

Java 8 i lambde pred testom – jesu li brže od „for“ petlji?

Otkad su lambda izrazi i aspekti funkcionalnog programiranja dodani u Javu s verzijom 8, predstavljali su najveću promjenu u jeziku od samog početka korištenja Jave 1995. godine, ali su postavili i poveća očekivanja od zajednice programera. Svi su željeli osim kraćeg programskog koda dobiti i brže izvršavanje programskog koda kod čestih operacija sa zbirkama kao što sortiranje, filtriranje, pretraživanje, pronalaženje ekstremnih vrijednosti i slično.

Prednosti lambdi temelje se na paradigmi funkcionalnog programiranja, lakšeg distribuiranja obrade zbirki u višenitnoj okolini i višestrukih jezgara procesora i korištenje Stream API-a. Mogućnost korištenja sučelja koje imaju samo jednu neimplementiranu metodu može znatno skratiti količinu koda koji je potrebno napisati da bi se postigne najčešće korištene funkcionalnosti. Samo upravljanje nitima kod izvršavanje najčešćih operacija je u potpunosti preuzeto od samog jezika te Java platforme i programer mora samo odabrati opciju korištenja tih funkcionalnosti. Stream API je moguće koristiti dodavanjem metoda „stream“ ili „parallelStream“ koje su kompatibilne s postojećim zbirkama u Javi.

Kako bi se lambe podvrgle „benchmark“ testiranju, rezultati su se usporedili s rezultatima izvođenja iteratora, „for“ petlji i komparatora nad istim skupom podataka. Prilikom testiranja korišteno je računalo s četverojezgrednim procesorom Intel Core i7-470MQ, 32 GB RAM memorije, SDD Samsung  850 EVO 500GB diskom, Eclipse Neon razvojnim okruženjem te Javom 8u121. Testiranje je obavljeno nad generiranim objektima sa pseudoslučajnim vrijednostima. Svako mjerenje je ponovljeno 10 puta i u obzir su uzete srednje vrijednosti. Korišteni domenski model se temelji na dvije klase, „Person“ i „Programmer“ koja nasljeđuje klasu „Person“ s atributima prikazanim na slici 1:

Slika 1. Domenski model klasa korištenih u testiranju

Za početak je potrebno implementirati algoritam za generiranje objekata klasa "Programmer" i "Person" s pseudoslučajnim vrijednostima kako bi rezultati bili što vjerniji. Podaci koji se generiraju su ime, prezime, datum rođenja, programski jezik s kojim programer radi, datum početka bavljenja programiranjem i iznos plaće. Programski kod za generiranje objekata izgleda ovako:

SecureRandom random = new SecureRandom();

List<Programmer> programmers = new ArrayList<>();

String characters = new String("ABCDEFGHIJKLMNOPRSTUVWXYZ");

 

LocalDateTime start = LocalDateTime.now();

            

//Generating objects

for (int i = 0; i < NUMBER_OF_OBJECTSi++) {

String firstName = generateString(randomcharactersSTRING_LENGTH);

       String lastName = generateString(randomcharactersSTRING_LENGTH);

       LocalDate birthDate = generateBirthDate();

       String programmingLanguage = generateRandomProgrammingLanguage(random);

       LocalDate programmingStartDate = generateProgrammingStartDate(birthDate);

       BigDecimal randomSalary = generateRandomSalary(random);

       Programmer programmer = new Programmer(firstNamelastNamebirthDate,

                           programmingLanguageprogrammingStartDaterandomSalary);

       programmers.add(programmer);

}

            

LocalDateTime end = LocalDateTime.now();

long milliseconds = start.until(end, ChronoUnit.MILLIS);

System.out.println("TIME: " + milliseconds + " ms");

Programski isječak 1. programski kod za generiranje objekata

Implementacija algoritma pretraživanja objekata u svrhu pronalaženja najmlađeg programera

Za testiranje brzine algoritama prvo je potrebno kreirati određeni broj objekata (10, 100, 1.000, 10.000, 100.000 itd.), spremiti ih u listu te krenuti s određivanjem zadanog rezultata kao što je traženje najmlađeg programera, programera s najvećom plaćom, filtriranje programera po imenu itd. Pronalaženje objekta koji ima karakteristike najmlađeg programera može se obaviti korištenjem iteratora, „for“ petlje, sortiranjem pomoću „Comparator“ objekta, sekvencijskog lambda streama i paralelnog lambda streama. Mjerenja su obavljena s različitim količinama objekata. Implementacije su prikazane u nastavku:

/**

 * It finds the jungest programmer by using operator.

 *

 * @param programmers

 * @return youngest programmer

 */

private static Programmer findTheYoungestProgrammerByIterator(List<Programmer> programmers) {

System.out.println("YOUNGEST PROGRAMMER (ITERATOR)");

       LocalDateTime start = LocalDateTime.now();

            

       Iterator<Programmer> iter = programmers.iterator();

       Programmer youngestProgrammer = programmers.get(0);

       iter.next();

            

while(iter.hasNext()) {

             Programmer newProgrammer = iter.next();

                          

if(newProgrammer.getBirthDate().isAfter(youngestProgrammer.getBirthDate())) {

                           youngestProgrammer = newProgrammer;

             }

       }

            

       System.out.println("RESULT: " + youngestProgrammer.getLastName() + " " +

youngestProgrammer.getFirstName());

      

       LocalDateTime end = LocalDateTime.now();

       long milliseconds = start.until(end, ChronoUnit.MILLIS);

       System.out.println("TIME: " + milliseconds + " ms");

            

       return youngestProgrammer;

}

      

/**

 * It finds the youngest programmer with foreach loop.

 *

 * @param programmers

 * @return youngest programmer

 */

private static Programmer findTheYoungestProgrammerForeachLoop(List<Programmer> programmers) {

System.out.println("YOUNGEST PROGRAMMER (FOREACH LOOP)");

       LocalDateTime start = LocalDateTime.now();

            

       Programmer youngestProgrammer = programmers.get(0);

            

       for(Programmer newProgrammer : programmers.subList(1, programmers.size())) {

                          

if(newProgrammer.getBirthDate().isAfter(youngestProgrammer.getBirthDate())) {

                           youngestProgrammer = newProgrammer;

             }

       }

            

       System.out.println("RESULT: " + youngestProgrammer.getLastName() + " " +

youngestProgrammer.getFirstName());

            

       LocalDateTime end = LocalDateTime.now();

       long milliseconds = start.until(end, ChronoUnit.MILLIS);

       System.out.println("TIME: " + milliseconds + " ms");

            

       return youngestProgrammer;

}

      

/**

 * It finds the youngest programmer with comparator method for sorting.

 *

 * @param programmers

 * @return youngest programmer

 */

private static Programmer findTheYoungestProgrammerSorting(List<Programmer> programmers) {

       System.out.println("YOUNGEST PROGRAMMER (SORTING WITH COMPARATOR)");

       LocalDateTime start = LocalDateTime.now();

            

       Collections.sort(programmersnew Comparator<Programmer>() {

             @Override

             public int compare(Programmer p1, Programmer p2) {

                    return p1.getBirthDate().compareTo(p2.getBirthDate());

             }

       });

            

       Programmer youngestProgrammer = programmers.get(programmers.size() - 1);

            

       System.out.println("RESULT: " + youngestProgrammer.getLastName() + " " +

youngestProgrammer.getFirstName());

            

       LocalDateTime end = LocalDateTime.now();

            

       long milliseconds = start.until(end, ChronoUnit.MILLIS);

       System.out.println("TIME: " + milliseconds + " ms");

            

       return youngestProgrammer;

}

      

/**

 * It finds the jungest programmer using sequential stream.

 *

 * @param programmers

 * @return youngest programmer

 */

private static Programmer findTheYoungestProgrammerLambdaSequential(List<Programmer> programmers) {

            

System.out.println("YOUNGEST PROGRAMMER (LAMBDA SEQUENTIAL STREAM)");

       LocalDateTime start = LocalDateTime.now();

            

       Programmer youngestProgrammer = programmers.stream()

                    .max(Comparator.comparing(Programmer::getBirthDate))

                    .get();

            

       System.out.println("RESULT: " + youngestProgrammer.getLastName() + " " +

youngestProgrammer.getFirstName());

            

       LocalDateTime end = LocalDateTime.now();

            

       long milliseconds = start.until(end, ChronoUnit.MILLIS);

       System.out.println("TIME: " + milliseconds + " ms");

            

       return youngestProgrammer;

}

      

/**

 * It finds the youngest programmer using parallel streams.

 *

 @param programmers

 * @return youngest programmer

 */

private static Programmer findTheYoungestProgrammerLambdaParallel(List<Programmer> programmers) {

            

System.out.println("YOUNGEST PROGRAMMER (LAMBDA PARALLEL STREAM)");

       LocalDateTime start = LocalDateTime.now();

            

       Programmer youngestProgrammer = programmers.parallelStream()

                    .max(Comparator.comparing(Programmer::getBirthDate))

                    .get();

            

       System.out.println("RESULT: " + youngestProgrammer.getLastName() + " " +

youngestProgrammer.getFirstName());

            

       LocalDateTime end = LocalDateTime.now();

      

       long milliseconds = start.until(end, ChronoUnit.MILLIS);

       System.out.println("TIME: " + milliseconds + " ms");

            

       return youngestProgrammer;

}

Programski isječak 2. Metode za traženje najmlađeg programera korištenjem odabranih strategija

Na slici 2. prikazana su trajanja izvršavanja algoritama u milisekundama za paralelne streamove, sekvencijalne streamove, pristup sa sortiranjem korištenjem komparatora, "for" petlje i iteratora.

Slika 2. Prikaz rezultata mjerenja trajanja prilikom traženja najmlađeg programera među 10 objekata (u milisekundama)

Prema dobivenim rezultatima je vidljivo da su konvencionalne metode ipak brže za manji broj objekata, a lambde pokazuju da na njihove performanse za jako mali broj objekata utječu interne aktivnosti optimizacije iskorištavanja svih jezgara procesora. Umjerenim povećavanjem broja objekata situacija se neznatno mijenja, a kod velikog broja objekata, rješenja temeljena na lambdama i streamovima ipak pokazuju najbolje rezultate, što je demonstrirano na sljedećim grafovima:

Slika 3. Prikaz rezultata mjerenja trajanja prilikom traženja najmlađeg programera među 100 objekata (u milisekundama)

Slika 4. Prikaz rezultata mjerenja trajanja prilikom traženja najmlađeg programera među 1.000 objekata (u milisekundama)

Slika 5. Prikaz rezultata mjerenja trajanja prilikom traženja najmlađeg programera među 10.000 objekata (u milisekundama)


Slika 6. Prikaz rezultata mjerenja trajanja prilikom traženja najmlađeg programera među 100.000 objekata (u milisekundama)

Slika 7. Prikaz rezultata mjerenja trajanja prilikom traženja najmlađeg programera među 1.000.000 objekata (u milisekundama)

Sumarizirani podaci bez uključivanja rješenja s "Comparatorom" (zbog preglednosti, jer "Comparator" daje znatno lošije rezultate od ostalih) prikazani su na ovom grafu:

Slika 8. Prikaz sumarnih rezultata mjerenja trajanja prilikom traženja najmlađeg programera od 10 do 1.000.000 objekata (u milisekundama)

Prema prikazanim rezultatima je vidljivo da za zbirke s manjim brojem podataka lambde daju neznatno lošije rezultate po pitanju izvođenja (doduše, razlika je samo u nekoliko milisekundi), ali programski kod je kraći, pregledniji i u skladu s konceptima paradigme funkcijskog programiranja. Kod većeg broja objekata sekvencijalni streamovi postižu još lošije rezultate, dok se performanse paralelnih streamova mogu usporediti s performansama iteratora i "for" petlji. Može se zaključiti da je kod većine operacija pretraživanja objekata po zadanom kriteriju kad je uključen razuman broj objekata manje bitno na koji način će se pretraživati pa se odluka o samim detaljima implementacije ostavlja programeru i njegovim preferencijama kod programiranja.

Implementacija algoritma pretraživanja objekata u svrhu pronalaženja programera s najvećom plaćom

Performanse pretraživanja objekata ne ovise samo o količini objekata, već i o tipu podataka koji se koristi kod pretraživanja. U sljedećem primjeru će se umjesto korištenja datuma koristiti tip podatka "BigDecimal" koji sadrži iznos plaće programera, a tražim će se programer s najvećom plaćom. Implementacija algoritama je prikazana u nastavku:

       /**     

        * It finds the programmer with the highest salary by iterator.

        *

        * @param programmers

        * @return

        */

       private static Programmer findTheProgrammerWithHighestSalaryByIterator(List<Programmer> programmers) {

             System.out.println("HIGHEST SALARY (ITERATOR)");

             LocalDateTime start = LocalDateTime.now();

            

             Iterator<Programmer> iter = programmers.iterator();

             Programmer programmerWithHighestSalary = programmers.get(0);

             iter.next();

            

             while(iter.hasNext()) {

                    Programmer newProgrammer = iter.next();

                    if(newProgrammer.getSalary().compareTo(programmerWithHighestSalary.getSalary()) == 1) {

                           programmerWithHighestSalary = newProgrammer;

                    }

             }

            

             System.out.println("RESULT: " + programmerWithHighestSalary.getLastName() + " " + programmerWithHighestSalary.getFirstName());

            

             LocalDateTime end = LocalDateTime.now();

             long milliseconds = start.until(end, ChronoUnit.MILLIS);

             System.out.println("TIME: " + milliseconds + " ms");

            

             return programmerWithHighestSalary;

       }

      

       /**

        * It finds the programmer with the highest salary by for loop.

        *

        * @param programmers

        * @return

        */

       private static Programmer findTheProgrammerWithHighestSalaryForLoop(List<Programmer> programmers) {

             System.out.println("HIGHEST SALARY (FOREACH LOOP)");

             LocalDateTime start = LocalDateTime.now();

            

             Programmer programmerWithHighestSalary = programmers.get(0);

            

             for(Programmer newProgrammer : programmers.subList(1, programmers.size())) {

                    if(newProgrammer.getSalary().compareTo(programmerWithHighestSalary.getSalary()) == 1) {

                           programmerWithHighestSalary = newProgrammer;

                    }

             }

            

             System.out.println("RESULT: " + programmerWithHighestSalary.getLastName() + " " + programmerWithHighestSalary.getFirstName());

            

             LocalDateTime end = LocalDateTime.now();

             long milliseconds = start.until(end, ChronoUnit.MILLIS);

             System.out.println("TIME: " + milliseconds + " ms");

            

             return programmerWithHighestSalary;

       }

      

       /**

        * It finds the programmer with the highest salary by using comparator and sorting.

        *

        * @param programmers

        * @return

        */

       private static Programmer findTheProgrammerWithHighestSalarySorting(List<Programmer> programmers) {

             System.out.println("HIGHEST SALARY (SORTING WITH COMPARATOR)");

             LocalDateTime start = LocalDateTime.now();

            

             Collections.sort(programmersnew Comparator<Programmer>() {

                    @Override

                    public int compare(Programmer p1, Programmer p2) {

                           return p1.getSalary().compareTo(p2.getSalary());

                    }

             });

            

             Programmer programmerWithHighestSalary = programmers.get(programmers.size() - 1);

            

             System.out.println("RESULT: " + programmerWithHighestSalary.getLastName() + " " + programmerWithHighestSalary.getFirstName());

            

             LocalDateTime end = LocalDateTime.now();

            

             long milliseconds = start.until(end, ChronoUnit.MILLIS);

             System.out.println("TIME: " + milliseconds + " ms");

            

             return programmerWithHighestSalary;

       }

      

       /**

        * It finds the programmer with the highest salary by sequential lambda.

        *

        * @param programmers

        * @return

        */

       private static Programmer findTheProgrammerWithHighestSalaryLambdaSerial(List<Programmer> programmers) {

            

             System.out.println("HIGHEST SALARY (LAMBDA SEQUENTIAL STREAM)");

             LocalDateTime start = LocalDateTime.now();

            

             Programmer programmerWithHighestSalary = programmers.stream().max(Comparator.comparing(Programmer::getSalary)).get();

            

             LocalDateTime end = LocalDateTime.now();

            

             System.out.println("RESULT: " + programmerWithHighestSalary.getLastName() + " " + programmerWithHighestSalary.getFirstName());

            

             long milliseconds = start.until(end, ChronoUnit.MILLIS);

             System.out.println("TIME: " + milliseconds + " ms");

            

             return programmerWithHighestSalary;

       }

      

       /**

        * It finds the programmer with the highest salary by parallel streams.

        *

        * @param programmers

        * @return

        */

       private static Programmer findTheProgrammerWithHighestSalaryLambdaParallel(List<Programmer> programmers) {

            

             System.out.println("HIGHEST SALARY (LAMBDA PARALLEL STREAM)");

             LocalDateTime start = LocalDateTime.now();

            

             Programmer programmerWithHighestSalary = programmers.parallelStream().max(Comparator.comparing(Programmer::getSalary)).get();

            

             LocalDateTime end = LocalDateTime.now();

            

             System.out.println("RESULT: " + programmerWithHighestSalary.getLastName() + " " + programmerWithHighestSalary.getFirstName());

            

              long milliseconds = start.until(end, ChronoUnit.MILLIS);

             System.out.println("TIME: " + milliseconds + " ms");

            

             return programmerWithHighestSalary;

     }

Programski isječak 3. Metode za traženje programera s najvećom plaćom korištenjem odabranih strategija

Rezultati mjerenja performansi su prikazani na sljedećem grafu. Kao što je vidljivo i u prošlom primjeru, na manjem broju objekata i dalje iterator i "for" petlja daju bolje rezultate, dok na većim količinama objekata korištenje paralelnih streamova ipak rezultira s najboljim vremenima. 

Slika 9. Prikaz rezultata mjerenja trajanja prilikom traženja programera s najvećom plaćom od 10 do 1.000.000 objekata (u milisekundama)

Implementacija algoritma filtriranja objekata prema zadanom kriteriju

S obzirom na to da korištenje lambda izraza ne daje uvijek najbolje performanse pretraživanja u usporedbi s korištenjem npr. "for" petlji, također je testirano filtriranje objekata po zadanim kriterijima. U nastavku su prikazane metode koje implementiraju pretraživanje objekata prema zadanom prezimenu (u String obliku), odnosno sadrži li prezime programera zadani substring. Implementacije metoda su prikazane u nastavku:

/**

        * It finds the programmer by name with iterator.

        *

        * @param name

        * @param programmers

        * @return

        */

       private static List<Programmer> findTheProgrammersByNameAndIterator(String name, List<Programmer> programmers) {

             System.out.println("PROGRAMMERS BY NAME (ITERATOR)");

             List<Programmer> filteredProgrammers = new ArrayList<>();

             LocalDateTime start = LocalDateTime.now();

            

             Iterator<Programmer> iter = programmers.iterator();

 

             while(iter.hasNext()) {

                    Programmer newProgrammer = iter.next();

                    if(newProgrammer.getLastName().contains(name)) {

                           filteredProgrammers.add(newProgrammer);

                    }

             }

            

             LocalDateTime end = LocalDateTime.now();

             long milliseconds = start.until(end, ChronoUnit.MILLIS);

             System.out.println("TIME: " + milliseconds + " ms");

            

             System.out.println("RESULT: " + filteredProgrammers.size() + " programmers.");

            

             return filteredProgrammers;

       }

      

       /**

        * It finds the programmer by name with for loop.

        *

        * @param name

        * @param programmers

        * @return

        */

       private static  List<Programmer> findTheProgrammersByNameAndForLoop(String name, List<Programmer> programmers) {

             System.out.println("PROGRAMMERS BY NAME (FOREACH LOOP)");

            

             List<Programmer> filteredProgrammers = new ArrayList<>();

            

             LocalDateTime start = LocalDateTime.now();

            

             for(Programmer newProgrammer : programmers) {

                    if(newProgrammer.getLastName().contains(name)) {

                           filteredProgrammers.add(newProgrammer);

                    }

             }

            

             LocalDateTime end = LocalDateTime.now();

             long milliseconds = start.until(end, ChronoUnit.MILLIS);

             System.out.println("TIME: " + milliseconds + " ms");

            

             System.out.println("RESULT: " + filteredProgrammers.size() + " programmers.");

            

             return filteredProgrammers;

       }

      

       /**

        * It finds the programmer by name and sequential stream.

        *

        * @param name

        * @param programmers

        * @return

        */

       private static List<Programmer> findTheProgrammersByNameAndLambdaSerial(final String name, List<Programmer> programmers) {        

             System.out.println("PROGRAMMERS BY NAME (LAMBDA SEQUENTIAL STREAM)");

            

             LocalDateTime start = LocalDateTime.now();

            

             List<Programmer> filteredProgrammers = programmers.stream()

                           .filter(p -> p.getLastName().contains(name))

                           .collect(Collectors.toList());

            

             LocalDateTime end = LocalDateTime.now();

 

             long milliseconds = start.until(end, ChronoUnit.MILLIS);

             System.out.println("TIME: " + milliseconds + " ms");

            

             System.out.println("RESULT: " + filteredProgrammers.size() + " programmers.");

            

             return filteredProgrammers;

       }

      

       /**

        * It finds the programmer by name and parallel stream.

        *

        * @param name

        * @param programmers

        * @return

        */

       private static List<Programmer> findTheProgrammersByNameAndLambdaParallel(final String name, List<Programmer> programmers) {

            

             System.out.println("PROGRAMMERS BY NAME (LAMBDA PARALLEL STREAM)");

             LocalDateTime start = LocalDateTime.now();

            

             List<Programmer> filteredProgrammers = programmers.parallelStream()

                           .filter(p -> p.getLastName().contains(name)).collect(Collectors.toList());

            

             LocalDateTime end = LocalDateTime.now();

            

             long milliseconds = start.until(end, ChronoUnit.MILLIS);

             System.out.println("TIME: " + milliseconds + " ms");

            

             System.out.println("RESULT: " + filteredProgrammers.size() + " programmers.");

            

             return filteredProgrammers;

       }

 

Programski isječak 4. Metode za filtriranje programera prema zadanom dijelu prezimena

Na sljedećem grafu su prikazani podaci o performansama za navedene načine filtriranja. Može se zaključiti da paralelni streamovi daju odmah u početku mjerenja na malom broju podataka vrlo dobre rezultate usporedive s filtriranjem korištenjem "for" petlji, a na većem broju objekata postaju najbolja opcija za filtriranje.

Slika 10. Prikaz rezultata mjerenja trajanja filtriranja objekata prema zadanom dijelu prezimena 10 do 1.000.000 objekata (u milisekundama)

Implementacija algoritma filtriranja objekata prema zadanom kriteriju

Jedna od popularnijih funkcionalnosti lambda izraza je grupiranje objekata. Za primjeru podatkovnog modela programera grupiranje se provodi u mape gdje su ključevi programski jezici u kojima programeri rade, a vrijednosti u mapi liste programera koji rade u tim programskim jezicima. Već u količini programskog koda je vidljivo koliko su "elegantnija" rješenja temeljena na lambda izrazima, a po pitanju performansi je moguće koristiti paralelne ili serijske streamove, ovisno o broju objekata koji se grupiraju, kako je prikazano u nastavku. Programske implementacije izgledaju ovako:

public static Map<String, List<Programmer>> convertToMapWithIterator(List<Programmer> programmers) {

            

             System.out.println("CONVERT TO MAP (ITERATOR)");

             LocalDateTime start = LocalDateTime.now();

            

             Map<String, List<Programmer>> map = new HashMap<>();

             Iterator<Programmer> iter = programmers.iterator();

            

             while(iter.hasNext()) {

                    Programmer programmer = iter.next();

                    if(map.containsKey(programmer.getPrimaryLanguage().toString())) {

                           map.get(programmer.getPrimaryLanguage()).add(programmer);

                    }

                    else {

                           List<Programmer> programmerList = new ArrayList<>();

                           programmerList.add(programmer);

                           map.put(programmer.getPrimaryLanguage(), programmerList);

                    }

             }

            

             LocalDateTime end = LocalDateTime.now();

            

             long milliseconds = start.until(end, ChronoUnit.MILLIS);

             System.out.println("TIME: " + milliseconds + " ms");

            

             return map;

       }

      

       public static Map<String, List<Programmer>> convertToMapWithForLoop(List<Programmer> programmers) {

            

             System.out.println("CONVERT TO MAP (FOR LOOP)");

             LocalDateTime start = LocalDateTime.now();

            

             Map<String, List<Programmer>> map = new HashMap<>();

            

             for(Programmer programmer : programmers) {

                    if(map.containsKey(programmer.getPrimaryLanguage().toString())) {

                           map.get(programmer.getPrimaryLanguage()).add(programmer);

                    }

                    else {

                           List<Programmer> programmerList = new ArrayList<>();

                           programmerList.add(programmer);

                           map.put(programmer.getPrimaryLanguage(), programmerList);

                    }

             }

            

             LocalDateTime end = LocalDateTime.now();

            

             long milliseconds = start.until(end, ChronoUnit.MILLIS);

             System.out.println("TIME: " + milliseconds + " ms");

            

             return map;

       }

      

       public static Map<String, List<Programmer>> convertToMapWithSerialStream(List<Programmer> programmers) {

            

             System.out.println("CONVERT TO MAP (SERIAL STREAM)");

             LocalDateTime start = LocalDateTime.now();

            

             Map<String, List<Programmer>> map =

                           programmers.stream().collect(Collectors.groupingBy(Programmer::getPrimaryLanguage));

            

             LocalDateTime end = LocalDateTime.now();

            

             long milliseconds = start.until(end, ChronoUnit.MILLIS);

             System.out.println("TIME: " + milliseconds + " ms");

            

             return map;

       }

      

       public static Map<String, List<Programmer>> convertToMapWithParallelStream(List<Programmer> programmers) {

            

             System.out.println("CONVERT TO MAP (PARALLEL STREAM)");

             LocalDateTime start = LocalDateTime.now();

            

             Map<String, List<Programmer>> map =

                           programmers.parallelStream().collect(Collectors.groupingBy(Programmer::getPrimaryLanguage));

            

             LocalDateTime end = LocalDateTime.now();

            

             long milliseconds = start.until(end, ChronoUnit.MILLIS);

             System.out.println("TIME: " + milliseconds + " ms");

            

             return map;

       }

Programski isječak 5. Metode za grupiranje programera prema programskom jeziku

 

Na sljedećem grafu je prikazano koliko vremena je svakom od načinu potrebno da grupira zadanu količinu objekata te je moguće zaključiti što je najbolje koristiti u kojem od tih slučajeva. Međutim, s obzirom na znatno manju količinu programskog koda koji je potrebno napisati u slučaju korištenja lambda izraza, ta opcija je sigurno najprivlačnija većini programera.

Slika 11. Prikaz rezultata mjerenja trajanja grupiranja objekata u mape prema programskim jezicima 10 do 1.000.000 objekata (u milisekundama)

 Zaključak

S obzirom na to da je Java 8 već duže vrijeme dostupna programerima, prirodno je da programeri koriste najnovije funkcionalnosti koje sadrži nova verzija programskog jezika, kao što su lambda izrazi. Međutim, osim smanjenja količine koda, performanse nisu uvijek bolje od "konvencionalnih" načina programiranja algoritama, pogotovo ako se složena logika može sažeti u samo jednu liniju programskog koda. Za manje količine objekata "for" petlje i dalje omogućavaju implementaciju najbržih algoritama za pretraživanje, filtriranje i grupiranje objekata, dok lambde svoje prednosti iskazuju kod velikih količina objekata. No, u praksi se vrlo rijetko događa da je potrebno obrađivati velike količine objekata (između 100.000 i 1.000.000) pa korištenje "for" petlji i dalje ostaje jedan od najjednostavnijih i najbržih načina implementacije spomenutih algoritama. Možda nove verzije Jave donesu neke novitete i unapređenja po pitanju lambda izraza, to nam ostaje za vidjeti i testirati :-)

 

 

 

 

 

 

Popularne teme
.NET ABAP ADFS Agile Always On Anemic Model Angular Azure Backbone BI BI projekti Bootstrap building people business inteligence Business Intelligence Change Chrome CI CITCON Claims compile Continuous Delivery continuous deployment Continuous Integration CSR d3js data data visualization Data visualization alati DDD dekompozicija dependency injection dinamička forma dinamički parametri dinamički query distribuirani razvoj Domain-Driven design DOP društvena odgovornost edge-based video analytics Eliminating waste enkapsulacija enterprise razvoj softvera ERP ETL Excel FIORI Frontend game Geopackage GPKG GIS Git Groovy heat map HICCUPS Hichert HTML IBCS interoperability invision IoT IPSO izvještavanje java java lambde benchmark JavaFX Javascript Jazz Build Engine JBE Jenkins jquery jqueryui jsfiddle JVM Kaizen Kanban KING ICT Kingovci Knockout kvaliteta leadership Lean M language Management Maven Metodologija microservices Microsoft mobile Mobility mockups moć monday game NetWeaver network nodejs OGC OKR open source optimizacija organizacija organizacijska struktura OutOfMemoryError outsourcing paginacija Performance performanse PERT PMI podatkovni skup pouzdanost Power BI Power Map Power Pivot Power Query Power View pretraga proces procjena Product Owner programming proizvod Project manager projektni plan radar Rational Team Concert razvoj tima Release resize responsive charts REST retrospektiva Rich-Domain model Roko Roić rolling wave planning RTC SAP scale scatterplot chart Scrum scrum team scrum tim service boundaries single responsibility principle Single Sign-On smart metering SoapUI social responsibility softver Software software prototyping Software Testing Club Spring Boot SQL standard sustav videonadzora svg Team team building team development Team Foundation Server terminski plan Testing tim timesheet timovi Toggl.com touch transakcijski nadzor tražilica Uspjeh Visual Studio vodstvo vodstvo leadership moć društvena odgovornost DOP social responsibility CSR vođenje projekata WBS Web Zagreb STC

PRIJAVA NA NEWSLETTER

Najnovije novosti iz ICT svijeta