Showing posts with label Streams. Show all posts
Showing posts with label Streams. Show all posts

Saturday, October 21, 2017

Exercises to study Java Stream API


In this blog post, we will study Stream API of Java 9 with several exercise questions. In these exercises, we will use two different domains: 
  • IMDB Movies
  • World Countries
Before we dive into the exercise questions, let's take a look at these domains:

IMDB Movies: We have three domain classes: Movie, Director and Genre. Each movie has a title, a year and a unique id assigned by Internet Movie DataBase (IMDB). Each movie has been directed by at least one director, and each director has many movies. Each movie belongs to at least one genre.

package com.example.domain;

import java.util.ArrayList;
import java.util.List;

public class Movie {
private int id;
   private String title;
   private int year;
   private String imdb;
   private List<Genre> genres;
   private List<Director> directors;

   {
      genres = new ArrayList<>();
      directors = new ArrayList<>();
   }

   public Movie() {
   }

   public Movie(int id, String title, int year, String imdb) {
      this.id = id;
      this.title = title;
      this.year = year;
      this.imdb = imdb;
   }

   // getters and setters

   @Override   
   public String toString() {
      return "Movie [title=" + title + ", year=" + year + "]";
   }
}


package com.example.domain;
import java.util.ArrayList;
import java.util.List;

public class Director {
   private int id;
   private String name;
   private String imdb;
   private List<Movie> movies= new ArrayList<>();

   public Director() {
   }

   public Director(int id, String name, String imdb) {
      this.id = id;
      this.name = name;
      this.imdb = imdb;
   }

   // getters and setters
   @Override   
   public String toString() {
      return "Director [id=" + id + ", name=" + name + ", imdb=" + imdb + "]";
   }
}

package com.example.domain;
public class Genre {
   private int id;
   private String name;

   public Genre() {
   }

   public Genre(int id, String name) {
      this.id = id;
      this.name = name;
   }

   // getters and setters
@Override
   public String toString() {
      return "Genre [id=" + id + ", name=" + name + "]";
   }

}

World Countries: There are two domain classes: Country and City. Each city belongs to a country defined by the attribute, countryCode. Each country has a unique code and has many cities.

package com.example.domain;

import java.util.ArrayList;
import java.util.List;

public class Country {
   private String code;
   private String name;
   private String continent;
   private double surfaceArea;
   private int population;
   private double gnp;
   private int capital;
   private List<City> cities;
   {
      cities = new ArrayList<>();
   }

   public Country() {
   }

   public Country(String code, String name, String continent, int population,
         double surfaceArea, double gnp, int capital) {
      this.code = code;
      this.name = name;
      this.continent = continent;
      this.surfaceArea = surfaceArea;
      this.population = population;
      this.capital = capital;
      this.gnp = gnp;
   }

   // getters and setters
   @Override   
   public String toString() {
      return "Country [ name=" + name + ", population=" + population + "]";
   }

}

package com.example.domain;

public class City {
   private int id;
   private String name;
   private int population;
   private String countryCode;

   public City() {
   }

   public City(int id, String name, String countryCode, int population) {
      this.id = id;
      this.name = name;
      this.population = population;
      this.countryCode = countryCode;
   }

   // getters and setters
   
   @Override   
   public String toString() {
      return "City [id=" + id + ", name=" + name + ", population=" + population + ", countryCode=" + countryCode + "]";
   };

}

EXERCISE #1

Find the highest populated city of each country:

package com.example.exercise;

import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import com.example.dao.CountryDao;
import com.example.dao.InMemoryWorldDao;
import com.example.domain.City;

public class Exercise1 {

   public static void main(String[] args) {
      CountryDao countryDao= InMemoryWorldDao.getInstance();
      List<City> highPopulatedCitiesOfCountries = countryDao.findAllCountries()
                .stream()
                .map( country -> country.getCities().stream().max(Comparator.comparing(City::getPopulation)))
                .filter(Optional::isPresent)
                .map(Optional::get)
                  .collect(Collectors.toList());
      highPopulatedCitiesOfCountries.forEach(System.out::println);
   }

}

The code given above will produce the following output:

City [id=3494, name=Auckland, population=381800, countryCode=NZL]
City [id=764, name=Suva, population=77366, countryCode=FJI]
City [id=2884, name=Port Moresby, population=247000, countryCode=PNG]
City [id=918, name=Les Abymes, population=62947, countryCode=GLP]
.
.
.
City [id=4067, name=Charlotte Amalie, population=13000, countryCode=VIR]
City [id=712, name=Cape Town, population=2352121, countryCode=ZAF]
City [id=538, name=Bandar Seri Begawan, population=21484, countryCode=BRN]
City [id=933, name=Tegucigalpa, population=813900, countryCode=HND]

EXERCISE #2

Find the most populated city of each continent:

package com.example.exercise;

import java.util.Comparator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import com.example.dao.CountryDao;
import com.example.dao.InMemoryWorldDao;
import com.example.domain.City;

public class Exercise2 {

    public static void main(String[] args) {
        CountryDao countryDao = InMemoryWorldDao.getInstance();
        final Predicate<Entry<String, Optional<City>>> isPresent = entry -> entry.getValue().isPresent();
        final BiConsumer<String, Optional<City>> printEntry =
                (k,v) -> {
                    City city = v.get();
                    System.out.println(k + ": City [ name= " + city.getName() + ", population= " + city.getPopulation() + " ]");
                };
        Collector<City, ?, Map<String, Optional<City>>> groupingHighPopulatedCitiesByContinent = Collectors.groupingBy(city -> countryDao.findCountryByCode(city.getCountryCode()).getContinent(), Collectors.maxBy(Comparator.comparing(City::getPopulation)));
        Map<String, Optional<City>> highPopulatedCitiesByContinent = countryDao.findAllCountries()
                .stream()
                .flatMap(country -> country.getCities().stream())
                .collect(groupingHighPopulatedCitiesByContinent);
        highPopulatedCitiesByContinent.forEach(printEntry);

    }

}

The code given above will produce the following output:

South America: City [ name= SÆo Paulo, population= 9968485 ]
Asia: City [ name= Mumbai (Bombay), population= 10500000 ]
Europe: City [ name= Moscow, population= 8389200 ]
Africa: City [ name= Cairo, population= 6789479 ]
North America: City [ name= Ciudad de M‚xico, population= 8591309 ]
Oceania: City [ name= Sydney, population= 3276207 ]


EXERCISE #3

Find the number of movies of each director: Try to solve this problem by assuming that Director class has not the member movies

package com.example.exercise;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.example.domain.Director;
import com.example.domain.Movie;
import com.example.service.InMemoryMovieService;
import com.example.service.MovieService;

public class Exercise3 {

    public static void main(String[] args) {
        MovieService movieService = InMemoryMovieService.getInstance();
        Collection<Movie> movies = movieService.findAllMovies();
        Map<String, Long> directorMovieCounts =
                movies.stream()
                        .map(Movie::getDirectors)
                        .flatMap(List::stream)
                        .collect(Collectors.groupingBy(Director::getName, Collectors.counting()));
        directorMovieCounts.entrySet().forEach(System.out::println);
    }

}


The code given above will produce the following output:

Sam Taylor Wood=1
F. Gary Gray=1
Oliver Hirschbiegel=1
Scott Cooper=1
Katherine Dieckmann=1
Kevin Macdonald=1
Peter Jackson=2
Andy Tennant=1
.
.
.
Isabel Coixet=1
Jason Reitman=1
Louie Psihoyos=1
Brian De Palma=1
Jay DiPietro=1

EXERCISE #4


Find the number of genres of each director's movies:

package com.example.exercise;

import java.util.Collection;
import java.util.Map;
import java.util.stream.Stream;

import com.example.domain.Director;
import com.example.domain.Genre;
import com.example.domain.Movie;
import com.example.service.InMemoryMovieService;
import com.example.service.MovieService;

import static java.util.stream.Collectors.*;

public class Exercise4 {

    public static void main(String[] args) {
        MovieService movieService = InMemoryMovieService.getInstance();
        Collection<Director> directors = movieService.findAllDirectors();
        Stream<DirectorGenre> stream =
                directors.stream()
                        .flatMap(director -> director.getMovies()
                                .stream()
                                .map(Movie::getGenres)
                                .flatMap(Collection::stream)
                                .map(genre -> new DirectorGenre(director, genre))
                                .collect(toList()).stream()
                        );
        Map<Director, Map<Genre, Long>> directorGenreList =
                stream.collect(
                        groupingBy(
                                DirectorGenre::getKey,
                                groupingBy(DirectorGenre::getValue, counting())
                        )
                );
        directorGenreList.forEach(
                (k1,v1) -> {
                    System.out.println(k1.getName());
                    v1.forEach( (k2,v2) -> {
                                System.out.println(String.format("\t%-12s: %2d", k2.getName(), v2));
                            });
                    System.out.println();
                }
        );
    }

}

class DirectorGenre implements Map.Entry<Director, Genre> {
    private Director director;
    private Genre genre;

    public DirectorGenre(Director director, Genre genre) {
        this.director = director;
        this.genre = genre;
    }

    @Override    public Director getKey() {
        return director;
    }

    @Override    public Genre getValue() {
        return genre;
    }

    @Override    public Genre setValue(Genre genre) {
        this.genre = genre;
        return genre;
    }

}

The code given above will produce the following output:

Marc Webb
 Comedy      :  1
 Drama       :  1
 Romance     :  1

Peter Hyams
 Drama       :  1
 Mystery     :  1

Mark Neveldine
 Action      :  1
 Sci-Fi      :  1
 Thriller    :  1

Brian Taylor
 Action      :  1
 Sci-Fi      :  1
 Thriller    :  1

.
.
.

Ryûhei Kitamura
 Fantasy     :  1
 Drama       :  1
 Action      :  1
 Thriller    :  1
 Adventure   :  1

Shusuke Kaneko
 Action      :  1

Gregor Jordan
 Drama       :  1
 Thriller    :  1

EXERCISE #5


Find the highest populated capital city:

package com.example.exercise;

import com.example.dao.CityDao;
import com.example.dao.CountryDao;
import com.example.dao.InMemoryWorldDao;
import com.example.domain.City;
import com.example.domain.Country;

import java.util.Objects;
import java.util.Optional;

import static java.lang.System.out;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.maxBy;

public class Exercise5 {

    public static void main(String[] args) {
        CountryDao countryDao = InMemoryWorldDao.getInstance();
        CityDao cityDao = InMemoryWorldDao.getInstance();
        Optional<City> capital = countryDao.findAllCountries()
                .stream()
                .map(Country::getCapital)
                .map(cityDao::findCityById)
                .filter(Objects::nonNull)
                .collect(maxBy(comparing(City::getPopulation)));
        capital.ifPresent(out::println);
    }

}

The code given above will produce the following output:

City [id=2331, name=Seoul, population=9981619, countryCode=KOR]

EXERCISE #6


Find the highest populated capital city of each continent:

package com.example.exercise;

import com.example.dao.CityDao;
import com.example.dao.CountryDao;
import com.example.dao.InMemoryWorldDao;
import com.example.domain.City;

import java.util.Map;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

import static java.lang.System.out;
import static java.util.Comparator.*;
import static java.util.stream.Collectors.*;

public class Exercise6 {

    public static void main(String[] args) {
        CountryDao countryDao = InMemoryWorldDao.getInstance();
        CityDao cityDao = InMemoryWorldDao.getInstance();
        Map<String, Optional<ContinentPopulatedCity>> continentsCapitals = countryDao.findAllCountries()
                .stream()
                .filter(country -> country.getCapital() > 0)
                .map(country -> new ContinentPopulatedCity(country.getContinent(), cityDao.findCityById(country.getCapital())))
                .collect(groupingBy(ContinentPopulatedCity::getKey, maxBy(comparing(cpc -> cpc.getValue().getPopulation()))));
        BiConsumer<String, Optional<ContinentPopulatedCity>> print= (k, v) -> {
            Consumer<ContinentPopulatedCity> continentPopulatedCityConsumer = cpc -> out.println(cpc.getKey() + ": " + v.get().getValue());
            v.ifPresent(continentPopulatedCityConsumer);
        };
        continentsCapitals.forEach(print);
    }

}

class ContinentPopulatedCity implements Map.Entry<String, City> {
    private String continent;
    private City city;

    public ContinentPopulatedCity(String continent, City city) {
        this.continent = continent;
        this.city = city;
    }

    @Override    public String getKey() {
        return continent;
    }

    @Override    public City getValue() {
        return city;
    }

    @Override    public City setValue(City city) {
        this.city = city;
        return city;
    }

}

The code given above will produce the following output:

South America: City [id=2890, name=Lima, population=6464693, countryCode=PER]
Asia: City [id=2331, name=Seoul, population=9981619, countryCode=KOR]
Europe: City [id=3580, name=Moscow, population=8389200, countryCode=RUS]
Africa: City [id=608, name=Cairo, population=6789479, countryCode=EGY]
North America: City [id=2515, name=Ciudad de M‚xico, population=8591309, countryCode=MEX]
Oceania: City [id=135, name=Canberra, population=322723, countryCode=AUS]

EXERCISE #7


Sort the countries by number of their cities in desending order:

package com.example.exercise;

import com.example.dao.CountryDao;
import com.example.dao.InMemoryWorldDao;
import com.example.domain.Country;

import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;

import static java.lang.String.format;
import static java.lang.System.out;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

public class Exercise7 {

    public static void main(String[] args) {
        CountryDao countryDao = InMemoryWorldDao.getInstance();
        Comparator<Country> sortByNumOfCities = comparing(country -> country.getCities().size());
        Predicate<Country> countriesHavingNoCities = country -> country.getCities().isEmpty();
        List<Country> countries = countryDao.findAllCountries()
                .stream()
                .filter(countriesHavingNoCities.negate())
                .sorted(sortByNumOfCities.reversed())
                .collect(toList());
        countries.forEach(country -> out.println(format("%38s %3d", country.getName(), country.getCities().size())));
    }

}

The code given above will produce the following output:

                               China 363
                               India 341
                       United States 274
                              Brazil 250
                               Japan 248
                  Russian Federation 189
                              Mexico 173
                                       .
                                       .
                                       .
                            Barbados   1
                              Tuvalu   1
                                Niue   1
                Virgin Islands, U.S.   1
                              Brunei   1

EXERCISE #8

Find the list of movies having the genres "Drama" and "Comedy" only:

package com.example.exercise;

import com.example.domain.Genre;
import com.example.domain.Movie;
import com.example.service.InMemoryMovieService;
import com.example.service.MovieService;

import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;

import static java.lang.String.format;
import static java.lang.System.out;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;

public class Exercise8 {

    public static void main(String[] args) {
        MovieService movieService = InMemoryMovieService.getInstance();
        Collection<Movie> movies = movieService.findAllMovies();
        Predicate<Movie> drama = movie -> movie.getGenres().stream().anyMatch(genre -> genre.getName().equals("Drama"));
        Predicate<Movie> comedy = movie -> movie.getGenres().stream().anyMatch(genre -> genre.getName().equals("Comedy"));
        Predicate<Movie> havingTwoGenresOnly = movie -> movie.getGenres().size() == 2;
        List<Movie> dramaAndComedyMovies = movies.stream()
                .filter(havingTwoGenresOnly.and(drama.and(comedy)))
                .collect(toList());
        dramaAndComedyMovies.forEach(movie -> out.println(format("%-32s: %12s", movie.getTitle(), movie.getGenres().stream().map(Genre::getName).collect(joining(",")))));
    }

}

The code given above will produce the following output:

Away We Go                      : Comedy,Drama
A Serious Man                   : Comedy,Drama
High Life                       : Comedy,Drama
Cold Souls                      : Comedy,Drama
Worlds Greatest Dad             : Comedy,Drama
My One and Only                 : Comedy,Drama
Sunshine Cleaning               : Comedy,Drama
The Vicious Kind                : Comedy,Drama
Defendor                        : Comedy,Drama
I Love You Phillip Morris       : Comedy,Drama

EXERCISE #9

Group the movies by the year and list them:

package com.example.exercise;

import com.example.domain.Movie;
import com.example.service.InMemoryMovieService;
import com.example.service.MovieService;

import java.util.Collection;
import java.util.Map;

import static java.lang.String.format;
import static java.lang.System.out;
import static java.util.Comparator.comparing;
import static java.util.Map.*;
import static java.util.stream.Collectors.*;

public class Exercise9 {

    public static void main(String[] args) {
        MovieService movieService = InMemoryMovieService.getInstance();
        Collection<Movie> movies = movieService.findAllMovies();
        Map<Integer, String> moviesByYear = movies.stream().collect(groupingBy(Movie::getYear, mapping(Movie::getTitle, joining(","))));
        moviesByYear.entrySet().stream().sorted(comparing(Entry::getKey)).forEach(entry -> out.println(format("%4d: %s", entry.getKey(), entry.getValue())));
    }

}

The code given above will produce the following output:

1940: The Return of Frank James
1944: Double Indemnity
1948: The Treasure of the Sierra Madre
1950: Sunset Blvd.
1951: A Streetcar Named Desire
1953: Stalag 17
1954: Them!,Shichinin no samurai,Dial M for Murder
1958: Vertigo
1960: Psycho
1963: The Great Escape
1968: The Party
1969: Butch Cassidy and the Sundance Kid,Easy Rider,The Wild Brunch
1973: Le magnifique
1975: Dog Day Afternoon
1976: Network,The Little Girl Who Lives Down the Lane
1977: Der amerikanische Freund,The Last Wave
1983: Rembetiko,Danton,The Outsiders,Scarface
1987: Empire of the Sun
1988: The Accused
1989: My Left Foot: The Story of Christy Brown
1991: My Own Private Idaho
1992: Of Mice and Men
1993: Tombstone,Germinal
1994: Before the Rain,Heavenly Creatures
1996: L appartement
1997: Bacheha-Ye aseman,The Rainmaker
2000: Almost Famous
2001: Yeopgijeogin geunyeo
2002: Ice Age
2003: Bom yeoreum gaeul gyeoul geurigo bom,Oldboy,Jeux Denfants,Keulraesik,Azumi
2004: Bin-jip,Nae meorisokui jiwoogae,Samaria,Wicker Park,2046,Voditel dlya Very
2005: Hiroshima,Hwal,Just Like Heaven,Azumi 2: Death or Love
2006: Deiji,Ice Age: The Meltdown,La Sconosciuta
2007: Paranormal Activity,Before the Devil Knows You are Dead,Broken English,Ex Drummer
2008: Adam Resurrected,Nothing But the Truth,100 Feet,Nordwand,The Other Man,God on Trial,Sunshine Cleaning,Oorlogswinter,Bin-mong,Pazar - Bir Ticaret Masalı,The Hurt Locker,My Only Sunshine,Karamazovi,Ghost Town,To Verdener,Sonbahar,Yip Man,Elegy,What Doesnt Kill You,Faubourg 36
2009: 500 Days Of Summer,Beyond a Reasonable Doubt,Gamer,Cheri,Dorian Gray,Inglourious Basterds,Invictus,Julie and Julia,Los abrazos rotos,Armored,Bornova Bornova,Coco avant Chanel,Nefes: Vatan sağolsun,Up,Whiteout,The Time Travelers Wife,Whatever Works,Anonyma - Eine Frau in Berlin,Zombieland,Weather Girl,Watchmen,Angels and Deamons,Away We Go,Last Ride,The Boys Are Back,The Tournament,A Serious Man,Saw VI,Ne te retourne pas,District 9,Extract,Five Minutes of Haven,High Life,The Proposal,Veronika Decides to Die,The Goods: Live Hard, Sell Hard,The Hangover,Public Enemies,Creation,Amelia,The Rebound,Powder Blue,The Men Who Stare at Goats,Bright Star,Case 39,Cold Souls,Moon,Worlds Greatest Dad,State of Play,The Brothers Bloom,My One and Only,Man Som Hatar Kvinnor,Mary and Max,The Limits of Control,A Perfect Getaway,My Sisters Keeper,Planet 51,I Love You, Man,Amelia,The Damned United,New York, I Love You,Fish Tank,The Informant!,The Courageous Heart of Irena Sendler,Storm,Triangle,2012,The Cry of the Owl,13B,El secreto de sus ojos,Surrogates,Kimssi pyoryugi,Uzak İhtimal,Daybreakers,Cairo Time,The Cove,Tenderness,Hachiko: A Dogs Story,The Box,Everybodys Fine,Peter and Vandy,Women in Trouble,Un prophete,The Vicious Kind,Bakjwi,Up in the air,Law Abiding Citizen,Nine,The Soloist,Agora,Motherhood,Neşeli Hayat,The Greatest,The Boondock Saints II: All Saints Day,The Private Lives of Pippa Lee,The Imaginarium of Doctor Parnassus,The Men Who Stare at Goats,Cloudy with a Chance of Meatballs,The Princess and the Frog,An Education,Avatar,Avatar 3D,Precious: Based on the Novel Push by Sapphire,The Blind Side,New Moon,Fantastic Mr. Fox,Sherlock Holmes,The Road,Man som hatar kvinnor,The Collector,Leaves of Grass,Brooklyns Finest,Alice,Duplicity,Harry Brown,Defendor,Brothers,Crazy Heart,Kıskanmak,Das weisse Band - Eine deutsche Kindergeschichte,The Lovely Bones,Eastern Plays,Cargo,Glorious 39,Fifty Dead Men Walking,Grey Gardens,Vavien,Lebanon,Harry Potter and the Half-Blood Prince,Slovenka,9:06,2081,The Electric Mist,Serious Moonlight,Ice Age: Dawn of the Dinosaurs,La doppia ora,A Single Man,Cracks,The Missing Person,Nowhere Boy,Chloe,Drag Me to Hell,Eloise's Lover,Başka Dilde Aşk,Air Doll
2010: From Paris with Love,Edge of Darkness,Shutter Island,The Bounty Hunter,Dear John,Extraordinary Measures,Leap Year,Yahşi Batı,I Love You Phillip Morris,You Dont Know Jack,Yip Man 2: Chung si chuen kei,Alice in Wonderland,Romantik Komedi,Veda,Sin Nombre,The Book of Eli,Unthinkable,Shrek Forever After


EXERCISE #10

Sort the countries by their population densities in descending order ignoring zero population countries:

package com.example.exercise;

import com.example.dao.InMemoryWorldDao;
import com.example.dao.WorldDao;
import com.example.domain.Country;

import java.util.Collection;
import java.util.Comparator;
import java.util.function.Predicate;

import static java.lang.System.out;
import static java.util.Comparator.comparingDouble;

public class Exercise10 {

    public static void main(String[] args) {
        WorldDao worldDao = InMemoryWorldDao.getInstance();
        Collection<Country> countries = worldDao.findAllCountries();
        Comparator<Country> populationDensityComparator = comparingDouble(country -> country.getPopulation() / country.getSurfaceArea());
        Predicate<Country> livesNobody = country -> country.getPopulation() == 0L;
        countries.stream().filter(livesNobody.negate()).sorted(populationDensityComparator.reversed())
                .forEach(out::println);
    }

}

The code given above will produce the following output:

Country [ name=Macao, population=473000]
Country [ name=Monaco, population=34000]
Country [ name=Hong Kong, population=6782000]
Country [ name=Singapore, population=3567000]
Country [ name=Gibraltar, population=25000]
.
.
.

Country [ name=Western Sahara, population=293000]
Country [ name=Pitcairn, population=50]
Country [ name=Falkland Islands, population=2000]
Country [ name=Svalbard and Jan Mayen, population=3200]
Country [ name=Greenland, population=56000]

You can download the source of the domain through this link.

Sunday, April 26, 2015

Java'da Diziler


Java'da değişkenleri çeşitli biçimlerde sınıflandırabiliriz:
  • Yerel değişken Bir metod bloğunda ya da metodun parametre listesinde tanımlanan değişkenler, yerel değişken olarak adlandırılırlar. Yığında saklanırlar. Bu nedenle bazen yığın değişkeni olarak da adlandırılır. Otomatik olarak yaratılır ve yine erimi dışına çıkınca otomatik olarak yok edilirler. Bu nedenle de bazen otomatik değişken olarak da isimlendirildiği de olur. Okumadan önce mutlaka ilklendirmek gerekir. Derleyici bu durumun takipçisidir!
  • Durum değişkeni Sınıf için tanımladığımız öznitelikler durum değişkeni olarak adlandırılır. Nesnenin durumunu oluştururlar. Bir sınıftan, her nesne yaratıldığında durum değişkenleri için prosesin Heap alanında yer ayrılır:
public class Circle {
    private double x;
    private double y;
    private double radius;
    private byte thickness;  
    private String color;

    . 
    . 
    .
}
Durum değişkenlerinin bellekte nasıl sıralanacaklarına Java Sanal Makinası (JSM) karar verir. Örneğin Circle sınıfı için CompressedOops özelliğinin açık olduğu 64-bitlik bir JSM'de aşağıdaki gibi bir dizilim gerçekleşir:
offset  size   type description
      0    12        (assumed to be the object header + first field alignment)
     12     1   byte Circle.tickness
     13     3        (alignment/padding gap)
     16     8 double Circle.x
     24     8 double Circle.y
     32     8 double Circle.radius
     40     4 String Circle.color
     44    20        (loss due to the next object alignment)
     64              (object boundary, size estimate)
Durum değişkenleri otomatik olarak ilklendirilir. İlklendirme değeri tamsayı ve kayan noktalı sayılar için 0, boolean için false ve tipi sınıf olan tüm değişkenler için ise null değeridir:
Veri Tipi
Varsayılan Değeri
boolean
false
char
\u0000
int,short,byte / long
0 / 0L
float /double
0.0f / 0.0d
Tüm referans tipler
null
  • Değer tipli değişken Tipi Java'daki temel tiplerden seçilmiş olan değişkenlerdir. Değişkenleri bellekte bir kutu olarak düşünebiliriz. Değer saklayan değişkenlerde, kutuyu açtığımızda, içinden tanımlandığı tipte bir değer ile karşılaşırız. Kutunun boyu, temel tipin tanımladığı uzunluktadır. Örneğin byte için bir sekizlik (1-Byte), long için 8 sekizlik (8-Byte), char için ise iki sekizlik olacaktır.
  • Referans değişkeni Temel tipler dışında, tipi bir sınıf olan değişkenler referans değişkenidir. Bu değişkenler için kutuyu açtığımızda içinden referans ettiği nesnenin adresi çıkar. 32-bit JSM için 32-bit ve 64-bit JSM için ise Heap alanının boyuna göre 32-bitten 64-bite kadar değişken uzunlukta olabilir.
  • Skalar değişken Skalar değişkenler sadece tek bir değer ya da nesnenin referansını saklayabilen değişkenlerdir:
int x= 42;
String name= "Jack";
double pi= 3.1415;
Circle blueUnitCircle= new Circle(0.,0.,1.,"Blue");
  • Dizi değişkeni Bazen bir değişkende birden fazla değer ya da nesne saklamak isteriz. Bu durumda dizilerden yararlanılır. Dizi tanımlamak kolaydır. Tek boyutlu bir dizi köşeli parantez çifti kullanılarak tanımlanabilir:

int lost[];
int []array;
Köşeli parantez çifti ([]) değişkenin önünde ya da arkasında kullanılabilir. Dizinin tanımını yaptık ama henüz bellek gözleri için yer almadık. Dizinin gözlerini yaratmak için farklı yöntemler kullanılabilir:
int lost[] = { 4, 8, 15, 16, 23, 42 };
int[] array;
int []dizi;
array = new int[] { 4, 8, 15, 16, 23, 42 };
dizi= new int[6];
dizi[0]= 4;
dizi[1]= 8;
dizi[2]= 15;
dizi[3]= 16;
dizi[4]= 23;
dizi[5]= 42;
int []lottery;
lottery= new Random().ints(1,49).distinct().limit(6).sorted().toArray();
int []sequence;
sequence= IntStream.range(1, 100).toArray();
Dizi elemanları bellekte ardışıl gözlerde saklanırlar. Dizi eleman sayısını bilir:
Şekil-1 Java'da diziler
Dizi gözlerine, gözün indisini köşeli parantez içerisinde vererek erişiyoruz. Dizi indisleri sıfırdan başlayarak adreslenir. Tamsayı değerler ile dolu bir dizinin elemanlarının toplamı için aşağıdaki çözümleri kullanabiliriz:
int[] sequence = IntStream.range(1, 100).toArray();
long sum = 0;
for (int i = 0; i < sequence.length; ++i) {
    sum += sequence[i];
}

int[] sequence = IntStream.range(1, 100).toArray();
long sum = 0;
for (int cell : sequence)
    sum += cell;

int[] sequence = IntStream.range(1, 100).toArray();
long sum = Arrays.stream(sequence).sum();
Dizinin gözlerine erişirken indisin sınırlar dışına çıkmadığından emin olun. Aksi halde yürütme zamanında IndexOutOfBoundsException hatası ile karşılaşırsınız. Neden böyle oldu? sorusunun yanıtını bulup, kodun bu hatayı üretmemesini sağlamalısınız! for-each (for (int cell : sequence)) yapısını kullanırsanız, zaten bu hata ile hiçbir zaman karşılaşmazsınız. Ancak bu yapının salt okunur olduğuna dikkat etmelisiniz: Mevcut dizide bir değişiklik yapamazsınız!
Circle[] circles = new Circle[10];
for (Circle circle: circles){
    circle= new Circle(0.,0.,1.,"Blue");
}
for (Circle circle: circles){
    System.err.println(circle.area());
}
Yukarıdaki kodu çalıştırırsanız, java.lang.NullPointerException hatasını alırsınız! Dizi gözlerinde değişiklik yapmak için her zaman indis üzerinde dönen bir döngü kurmanız gerekir:
Circle[] circles = new Circle[10];
for (int i=0;i<circles.length;++i){
    circles[i] = new Circle(0.,0.,1.,"Blue");
}
for (Circle circle: circles){
    System.err.println(circle.area());
}
Eğer temel tipler üzerinde aritmetik işlem yapmak üzere bir dizi oluşturacaksanız, diziyi mutlaka temel tipten tanımlayın, sakın sarmal sınıftan tanımlamayın! 
Şekil-2 Integer tipinden bir dizinin bellekteki yerleşimi
Şekil-3 int tipinden bir dizinin bellekteki yerleşimi

Hem bellekte hem de çalışma süresinde kaybedersiniz:
package com.example.test;

public class TestWrapperPrimitiveArrays {
 private static final int LOOP_COUNT = 50;
 private static Integer[] bigIntegerArray = new Integer[1_000_000];
 private static int[] bigIntArray = new int[1_000_000];
 static {
  for (int i = 0; i < bigIntegerArray.length; ++i)
      bigIntegerArray[i] = new Integer(1);
  for (int i = 0; i < bigIntegerArray.length; ++i)
      bigIntArray[i] = 1;
 }

 public static void main(String[] args) {
  System.err.println("Wrapper");
  for (int i = 0; i < LOOP_COUNT; ++i)
      runWrapper();
  System.err.println("Primitive");
  for (int i = 0; i < LOOP_COUNT; ++i)
      runPrimitive();
 }

 public static void runWrapper() {
  long startTime = System.nanoTime();
  long sum = 0;
  for (Integer x : bigIntegerArray)
      sum += x;
  long stopTime = System.nanoTime();
  System.err.println("Sum: " + sum + " @ " + (stopTime - startTime));
 }

 public static void runPrimitive() {
  long startTime = System.nanoTime();
  long sum = 0;
  for (int x : bigIntArray)
      sum += x;
  long stopTime = System.nanoTime();
  System.err.println("Sum: " + sum + " @ " + (stopTime - startTime));
 }

}
Bir Integer tipinde nesne bellekte 16 Byte yer kaplar, buna karşılık olarak int tipi ise sadece 4 Byte! 1 milyon elemanlı dizi için toplam harcanan bellek miktarı, referanslar da dahil olmak üzere, Integer tercihi (Şekil-2) için 20 milyon Byte ve int tercihi (Şekil-3) için ise 4 milyon Byte olacaktır. int tipini tercih ederseniz kapladığı alan beşte birine düşüyor! Çalışma zamanları karşılaştırıldığında ise int tipi dizi üzerinde elemanları toplamak için geçen süre, Integer tipindeki dizinin elemanlarını toplamak için geçen sürenin  üçte biri kadardır. Kazanan yine temel tip: int!
İki Boyutlu Diziler 
İki boyutlu dizileri matris olarak adlandırıyoruz. Matris tanımlamak, tek boyutlu dizi tanımlamaktan çok farklı değil. İki boyutlu olduğunu belirtmek için köşeli parantez çiftinden iki tane kullanıyoruz: 
int [][]unitMatrix= {
 {1, 0, 0}, 
 {0, 1, 0}, 
 {0, 0, 1} 
};
Genel olarak n-boyutlu bir dizi tanımlamak için n adet köşeli parantez çifti kullanılır. Çok boyutlu diziler bellekte satır düzeninde yerleşirler. Bu nedenle, unitMatrix[0] birinci satırı, unitMatrix[1] ikinci satırı ve elbette unitMatrix[2] üçüncü satırı tanımlar. unitMatrix.length matrisin satır sayısını verir. Matris kare matris ise satır sayısı sütun sayısına eşit olacaktır. Bu durumda, unitMatrix.lengthunitMatrix[0].lengthunitMatrix[1].lengthunitMatrix[2].length değerlerinin hepsi biri birine eşit olacaktır. Java'da matrisin satırlarında farklı sayılarda eleman bulunabilir. Matrisi farklı şekillerde tarayabiliriz:
int[][] unitMatrix = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
for (int i=0;i<unitMatrix.length;++i){
   int []row= unitMatrix[i];
   System.err.println(Arrays.toString(row));
}

int[][] unitMatrix = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
for (int[] row : unitMatrix) {
    System.err.println(Arrays.toString(row));
}

int[][] unitMatrix = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
Arrays.stream(unitMatrix)
      .map(Arrays::toString)
      .forEach(System.err::println);
Yukarıdaki her üç kod parçası için de ekran çıktısı aşağıdaki gibi gerçekleşir:
[1, 0, 0]
[0, 1, 0]
[0, 0, 1]
Diziler Üzerinde Paralel İşlemler
Java 8 ile çok çekirdekli platformlar üzerinde paralel koşan uygulamalar geliştirebiliyoruz. Bu bölümde, büyük veriler işlenirken sıklıkla kullanılan temel vektör ve matris işlemlerinin, Stream API ve Lambda ifadeleri kullanılarak, nasıl gerçekleştirildiğini çalışacağız. Önce vektör iç çarpımını ele alalım.
Vektör İç Çarpımı
u ve v gibi iki vektörün iç çarpımı aynı indisli elemanlarının çarpımının toplamı olarak tanımlanır:
$$\langle u , v \rangle = \sum_{i=1}^{n}u_i v_i$$. Bu tanım hem seri olarak hem de Java 8'de gelen paralel stream kullanılarak gerçeklenebilir:

package com.example.test;

import java.util.Random;
import java.util.function.BiFunction;
import java.util.stream.IntStream;

public class DotProductExample {
 private static final int ARRAY_SIZE = 300_000_000;
 private static final int LOOP_COUNT = 50;
 static int[] u;
 static int[] v;
 static {
  System.err.print("Populating u...");
  u = new Random().ints(0, 2).limit(ARRAY_SIZE).toArray();
  System.err.print("Done.\nPopulating v...");
  v = new Random().ints(0, 2).limit(ARRAY_SIZE).toArray();
  System.err.print("Done.\n");
 }

 public static void main(String[] args) {
  for (int i = 1; i <= LOOP_COUNT; ++i) {
   run(i, "Serial", DotProductExample::dotProductSerial);
  }
  for (int i = 1; i <= LOOP_COUNT; ++i) {
   run(i, "Stream", DotProductExample::dotProductStream);
  }
 }

 private static void run(int runNo, String method,
   BiFunction<int[], int[], Integer> productFunction) {
  long startTime = System.nanoTime();
  int product = productFunction.apply(u, v);
  long stopTime = System.nanoTime();
  System.err.println(String.format("[%-8s][%3d]:[%10d]@[%10d]", method,
    runNo, product, stopTime - startTime));
 }

 private static Integer dotProductSerial(int[] u, int[] v) {
  int sum = 0;
  for (int i = 0; i < u.length; ++i)
   sum += u[i] * v[i];
  return sum;
 }

 private static Integer dotProductStream(int[] u, int[] v) {
  return IntStream.range(0, u.length).parallel().map(i -> u[i] * v[i])
    .sum();
 }

}
Matris Çarpımı
A ve B gibi iki matrisin çarpımı,
$$
C_{m,n} = A_{m,s} \times B_{s,n}
$$
$$
A_{m,s} =
\begin{pmatrix}
a_{1,1} & a_{1,2} & \cdots & a_{1,s} \\
a_{2,1} & a_{2,2} & \cdots & a_{2,s} \\
\vdots & \vdots & \ddots & \vdots \\
a_{m,1} & a_{m,2} & \cdots & a_{m,s}
\end{pmatrix},
B_{s,n} =
\begin{pmatrix}
b_{1,1} & b_{1,2} & \cdots & b_{1,n} \\
b_{2,1} & b_{2,2} & \cdots & b_{2,n} \\
\vdots & \vdots & \ddots & \vdots \\
b_{s,1} & b_{s,2} & \cdots & b_{s,n}
\end{pmatrix},
C_{m,n} =
\begin{pmatrix}
c_{1,1} & c_{1,2} & \cdots & c_{1,n} \\
c_{2,1} & c_{2,2} & \cdots & c_{2,n} \\
\vdots & \vdots & \ddots & \vdots \\
c_{m,1} & c_{m,2} & \cdots & c_{m,n}
\end{pmatrix}
$$
$$
c_{i,j} = \sum_{k=1}^{k=s} a_{i,k} b_{k,j}
$$
biçiminde tanımlanır. Bu tanıma uygun olarak çarpımı hem seri olarak hem de Stream API kullanarak hesaplayan kodu aşağıda bulabilirsiniz.
package com.example.test;

import java.util.Arrays;
import java.util.stream.IntStream;

public class MatrixProductExample {
 private static final int LOOP_COUNT = 25;
 private static final int A_ROW_SIZE = 3000;
 private static final int A_COL_SIZE = 400;
 private static final int B_ROW_SIZE = 400;
 private static final int B_COL_SIZE = 5000;
 private static final int C_ROW_SIZE = 3000;
 private static final int C_COL_SIZE = 5000;
 private static final int[][] A;
 private static final int[][] B;
 private static final int[][] C;

 static {
  A = new int[A_ROW_SIZE][A_COL_SIZE];
  B = new int[B_ROW_SIZE][B_COL_SIZE];
  C = new int[C_ROW_SIZE][C_COL_SIZE];
  System.err.print("Populating A...");
  populateMatrix(A);
  System.err.print("Done.\nPopulating B...");
  populateMatrix(B);
  System.err.print("Done.\n");
 }

 private static void populateMatrix(int[][] A) {
  int rowSize = A.length;
  int colSize = A[0].length;
  IntStream.range(0, rowSize * colSize)
           .map(i -> {
                int row = i / colSize;
                int col = i % colSize;
                A[row][col] = row + col;
                return 0;
             }).sum();
 }

 public static void main(String[] args) {
  System.err.println("Matrix multiplication using Stream API.");
  for (int i = 1; i <= LOOP_COUNT; ++i)
      runStream();
  System.err.println("Matrix multiplication using 3x \"for\" loops.");
  for (int i = 1; i <= LOOP_COUNT; ++i)
      runStream();
 }

 public static void runSerial() {
  long startTime = System.nanoTime();
  productSerial(A, B, C);
  long stopTime = System.nanoTime();
  System.err.println(stopTime - startTime);
 }

 public static void runStream() {
  long startTime = System.nanoTime();
  productStream(A, B, C);
  long stopTime = System.nanoTime();
  System.err.println(stopTime - startTime);
 }

 public static void productStream(int[][] A, int[][] B, int[][] C) {
  int rowSizeA = A.length;
  int colSizeA = A[0].length;
  int colSizeB = B[0].length;
  IntStream.range(0, rowSizeA * colSizeB)
           .parallel()
           .map(i -> {
                  int row = i / colSizeB;
                  int col = i % colSizeB;
                  C[row][col] = 0;
                  for (int j = 0; j < colSizeA; ++j)
                      C[row][col] += A[row][j] * B[j][col];
                  return 0;
            }).sum();
 }

 public static void productSerial(int[][] A, int[][] B, int[][] C) {
  int rowSizeA = A.length;
  int colSizeA = A[0].length;
  int colSizeB = B[0].length;
  for (int i = 0; i < rowSizeA; ++i) {
      for (int j = 0; j < colSizeB; ++j) {
          C[i][j] = 0;
          for (int k = 0; k < colSizeA; ++k)
              C[i][j] += A[i][k] * B[k][j];
      } 
   }
 }

 private static void print(int[][] A) {
  Arrays.stream(A).map(Arrays::toString).forEach(System.err::println);
 }
}
i7 işlemcili dizüstü bilgisayarımda yukarıdaki uygulamayı çalıştırdığımda, seri çözüm ortalama 80 saniyede, Stream API tabanlı çözüm ise 25 saniyede tamamlandı. Çekirdek sayısına yakın bir hızlanmaya işaret ediyor. Yaşasın yeni kral: Java 8!
Metod Parametresi Olarak Diziler
Dizileri metotlara parametre olarak geçebiliriz. Bunun için metod parametresini dizi türünden tanıtmamız yeterli olacaktır:
public static long sumIf(int[] values, Predicate<Integer> constraint) {
 long sum = 0;
 for (int value : values) {
  if (constraint.test(value))
   sum += value;
 }
 return sum;
}
Stream API kullanarak bu çözümü daha yalın olarak tanımlayabiliriz:
public static long sumIf(int[] values, IntPredicate constraint) {
 return Arrays.stream(values).filter(constraint).sum();
}
sumIf fonksiyonunu çağırmak için önce bir dizi yaratmamız gerekiyor:
public static void main(String[] args) {
 int[] bigData = new Random().ints(1, 10000)
                       .limit(SIZE)
                       .toArray();
 sumIf(bigData, i -> i > 0 && i < 100);
}
Fonksiyona dizi türünde parametre geçmek için Java SE 5 ile bir diğer gösterim daha bulunuyor. Üç nokta (...) gösterimini, C programlama dilinden de biliyoruz. Metodun değişken sayıda parametre alacağını ifade ediyor. Gerçekte, fonksiyona verdiğimiz parametreler, derleyici tarafından diziye dönüştürülür ve dizi olarak çağrılır. Dizi oluşturmak için kod yazmakla gereksiz vakit kaybedilmemiş olur. Bu özellik, sadece gösterim kolaylığı sağlar. Üç nokta ile tanımlanan parametreyi dizi ile de doğrudan çağırabilirsiniz.
private static final int SIZE = 5000;

public static long sumIf(IntPredicate constraint, int... values) {
 return Arrays.stream(values).filter(constraint).sum();
}

public static void main(String[] args) {
 int[] bigData = new Random().ints(1, 10000).limit(SIZE).toArray();
 sumIf(i -> i > 0 && i < 100, bigData);
 sumIf(i -> i / 2 != 0, 4, 8, 15, 16, 23, 42);

}
Uymanız gereken iki basit temel kural var:
1. Üç nokta mutlaka metodun parametre listesinde sonda yer almalıdır
2. Birden fazla üç nokta tanımlaması yer alamaz.
Java 9+'da Diziler ile İlgili Yenilikler
Java 9 ve sonrasında diziler ile ilgili bizi bekleyen önemli iki gelişme bulunuyor. Bunlardan ilki sadece değer taşıyan durumu değiştirilemez (=Immutable) nesnelerin belleğe etkin yerleşimi ile ilgilidir. Örneğin, görüntüyü oluşturan benekleri Pixel adlı bir sınıfta modelleyelim:
public class Pixel {
    int red;
    int green;
    int blue; 
    double alpha; // 0 <= alpha <= 1
}
Pixel tipinden bir dizi tanımlarsak, belleğe Şekil-4'deki gibi yerleşecektir ve bu yerleşimin hiç verimli olmadığı açıktır. Hem kapladığı alan gereğinden fazladır hem de bellekte ardışıl gözlere yerleşmedikleri için cep bellekte çok sayıda ıskalama yapacaktır.
Şekil-4 Pixel tipinden bir dizinin bellekteki yerleşimi
Bu problemleri çözmek için Pixel sınıfını "value class" olarak tanımlıyoruz:
value public class Pixel {
    final int red;
    final int green;
    final int blue; 
    final double alpha;
    . . . 
}
Şimdi yerleşim bir öncekinden farklı olarak ardışıl olacaktır:
Şekil-5 Pixel tipinden bir dizinin "value class" olarak bellekteki yerleşimi
Elbette "value class"'larda hala çok şekillilik çalışmaya devam ediyor! Generics çatısında buna paralel bir değişiklik bekliyoruz:
new ArrayList<int>()
Evet, artık tip parametresi olarak temel tip verebiliyoruz! Burada JSM, yürütme zamanında yeni bir sınıf yaratıyor: ArrayList${T=int}.class. Bu durum bana hiç yabancı gelmedi: C++'da üretken programlama zaten bu şekilde çalışıyor!
Bu konudaki gelişmeleri aşağıdaki bağlantılardan takip edebilirsiniz: