"Pobieranie" wartości z kolekcji List i Map

0

Cześć, mam dwa pytania związane z "pobieraniem" (wyświetlaniem?) wartości z kolekcji typu List i Map. Najpierw zacznę od Listy, napisałem taki przykładowy programik:

package test1;

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

class Klasa1{
    int a; int b;
    
    Klasa1(){a=0; b=0;};
    Klasa1(int a, int b){this.a=a; this.b=b;};
    
    void show(){
        System.out.println("A = "+a+"; B = "+b);
    }
}


public class Test1 { 

   
    public static void main(String[] args) 
    throws java.io.IOException{
        
       int i=0;
       
       List<Klasa1> lista = new ArrayList<Klasa1>();
       
       while(i<3){
           lista.add(new Klasa1(i,i+1));
           i++;
       }i=0;
       
      
       
       while(i<lista.size()){
           System.out.println("Indeks elementu: "+i);
           lista.get(i).show();
           System.out.println();
           i++;
           
       }
        
    }
    
}

I teraz pytanie: czy pobranie elementu z listy w taki sposób i jednoczesne wywołanie metody z klasy, która jest elementem listy jest napisane dobrze? Chodzi mi konkretnie o tą linijkę kodu:

lista.get(i).show();

Czy jest to jak najbardziej poprawne? Nie znalazłem nigdzie takie zapisu, po prostu sam napisałem po indeksie kropkę i wywołałem metodę show() i okazało się, że działa.

Drugie pytanie dotyczące Map, program bardzo podobny do poprzedniego (w sumie w konsoli działa w identyczny sposób):


package mapa;


import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

class Klasa1{
    int a; int b;
    
    Klasa1(){a=0; b=0;};
    Klasa1(int a, int b){this.a=a; this.b=b;};
    
    void show(){
        System.out.println("A = "+a+"; B = "+b);
    }
}


public class Mapa {

    
    public static void main(String[] args) {
        
        Map<Integer, Klasa1> mapa = new HashMap<>();
        int i=0;
        
        while(i<3){
           mapa.put(i, new Klasa1(i,i+1));
           i++;
        } i=0;
        
        Klasa1 ob1 = new Klasa1();
        
        while(i<3){
           ob1 = mapa.get(i);
           System.out.println("Klucz elementu: "+i);
           ob1.show();
           System.out.println();
           i++;
        }
        
    }
    
}

Tutaj nie wiedziałem jak wyświetlić wartość wszystkich wartości w Mapie, więc od biedy stworzyłem nowy obiekt typu Klasa1 o referencji ob1 i w każdej iteracji pętli przypisywałem do niego kolejną wartość z Mapy. Niby działa, ale czy jest to ok? I czy można napisać to podobnie, jak zrobiłem w przypadku listy, czyli mniej więcej coś takiego:

mapa.get(i).show() //nie zadziałało

I na koniec: Jak mamy Mapę, to mam rozumieć, że w ostrych nawiasach najpierw mamy klucz, a potem wartość? Czyli gdybym zadeklarował Mapę odwrotnie, jak to zrobiłem w powyższym przykładzie, czyli:

Map<Klasa1, Integer> mapa = new HashMap<>();

To wtedy kluczem byłby obiekt typu Klasa1, a wartością jakiś obiekt Integer?

1
  1. sam napisałem po indeksie kropkę i wywołałem metodę show() i okazało się, że działa.

Działa ponieważ zadeklarowałeś liste obiektów typu Klasa1. Metodą get(i) pobierasz elementy z listy o indeksie i. Dodanie kropki pokazało Ci możliwe metody ponieważ pobrany obiekt jest typu Klasa1, więc możesz na nim wywołać te metody, które masz w tej klasie.

  1. mapa.get(i).show()

Nie zadziałało ponieważ mapa przyjmuje PARĘ obiektów, więc metoda get musi przyjąć obiekt który jest kluczem, następnie (jeśli taki obiekt istnieje w mapie) otrzymasz wartość do niego przypisaną.

  1. To wtedy kluczem byłby obiekt typu Klasa1, a wartością jakiś obiekt Integer?

Tak

0

Dobra, to mam jeszcze jedno pytanie: dopiero teraz zauważyłem błąd w drugim przykładzie, w pętli, która wyświetla wartości z Mapy:

while(i<3){
           ob1 = mapa.get(i);
           System.out.println("Klucz elementu: "+i);
           ob1.show();
           System.out.println();
           i++;
        }

W linijce, gdzie wyświetlany jest klucz elementu wstawiłem zwykłą zmienną iteracyjną, a w rzeczywistości powinna być pobierana wartość klucza każdego elementu. Jak ją pobrać?

1

Z jakiego IDE korzystasz programująć? Większość (jak nie wszystkie?) mocno podpowiadają podczas pisania kodu i pokazują co jest nie tak.

Aby użyć metody get na mapie (i uzyskać obiekt z kolekcji), musisz podać jako argument konkretny obiekt (typu którego jest KLUCZ mapy), dzięki temu uzyskasz od razu wartość przypisaną (sparowaną) do klucza.

0

Mam prośbę: czy mógłbyś (lub ktoś inny) zmodyfikować program nr 2, żeby działał? Próbuję to zrobić, ale nie potrafię. :/
Mam takie coś:


package mapa;


import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

class Klasa1{
    int a; int b;
    
    Klasa1(){a=0; b=0;};
    Klasa1(int a, int b){this.a=a; this.b=b;};
    
    void show(){
        System.out.println("A = "+a+"; B = "+b);
    }
}


public class Mapa {

    
    public static void main(String[] args) {
        
        Map<Integer, Klasa1> mapa = new HashMap<>();
        int i=0; Integer a;
        Scanner scan = new Scanner(System.in);
        
        System.out.println("Podaj numery klucza trzech obiektów typu Klasa1: ");
        
        while(i<3){ //w tej pętli musimy podać wartości kluczy trzech elementów z Mapy
           System.out.println("Klucz elementu "+(i+1)+": ");
           a = scan.nextInt(); scan.nextLine(); //tutaj podajemy numer klucza, jaki chcemy
           mapa.put(a, new Klasa1(i,i+1));
           i++;
        } i=0;
        
        Klasa1 ob1 = new Klasa1();
        
        while(i<3){
           ob1 = mapa.get(i);
           System.out.println("Klucz elementu: "+mapa.get(i)); //tutaj powinno wyświetlać wartość klucza każdego elementu
           ob1.show();
           System.out.println();
           i++;
        }
        
        System.out.println("Podaj numer klucza, aby usunąć dany element z mapy: ");
        //Tutaj dalej chciałbym dodać opcje usuwania elementu o konkretnym kluczu i ponowne wyświetlenie Mapy   
    }
    
}
0

Nie zrobię Ci tego, bo to są "zadania" na podstawowe użycia metod: put/get/remove. Jeśli chcesz się zapoznać z kolekcjami, musisz sam to rozwiązać. Serio, nie ma tu nic trudnego. Wczytaj się w opis konkretnej metody oraz co ona przyjmuje / zwraca. Nic więcej nie potrzeba.

https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html

EDIT: jeśli jesteś z angielskim na bakier, to tutaj masz opisane łopatologicznie po polsku: https://www.samouczekprogramisty.pl/kolekcje-w-jezyku-java/#mapa

0

Trochę mnie nie było, bo miałem inne rzeczy do roboty, ale w końcu udało mi się to ogarnąć w przypadku Mapy. Czy może być coś takiego:

package mapa;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

import java.util.Map.Entry;
import java.util.Set;

class Klasa1{
    int a; int b;
    
    Klasa1(){a=0; b=0;};
    Klasa1(int a, int b){this.a=a; this.b=b;};
    
    void show(){
        System.out.println("A = "+a+"; B = "+b);
    }
}


public class Mapa {

    
    public static void main(String[] args) {
        
        Map<Integer, Klasa1> mapa = new HashMap<>();
        int i=0; Integer a;
        Scanner scan = new Scanner(System.in);
        
        System.out.println("Podaj numery klucza trzech obiektów typu Klasa1: ");
        
        while(i<3){
           System.out.println("Klucz elementu "+(i+1)+": ");
           a = scan.nextInt(); scan.nextLine();
           mapa.put(a, new Klasa1(i,i+1));
           i++;
        } i=0; 
        Klasa1 ob1 = new Klasa1();
        
        System.out.println("W Mapie są następujące elementy:");
        
        int j=1;
        for(Map.Entry<Integer, Klasa1> entry : mapa.entrySet()){
            System.out.println("\nWartość klucza klasy nr "+j+" z mapy: "+entry.getKey());
            System.out.println("Wartość pól tej klasy: ");
            ob1 = mapa.get(entry.getKey());
            ob1.show();
            j++;
        } j=0;
        
        System.out.println("Jaki element chcesz usunąć z Mapy (podaj klucz): ");
        a = scan.nextInt(); scan.nextLine();
        mapa.remove(a);
        System.out.println("Usunięto element o kluczu = "+a);
        
        System.out.println("\nPonowne wyświetlenie zawartości Mapy, po usunięciu elementu: ");
        for(Map.Entry<Integer, Klasa1> entry : mapa.entrySet()){
            System.out.println("\nWartość klucza klasy nr "+j+" z mapy: "+entry.getKey());
            System.out.println("Wartość pól tej klasy: ");
            ob1 = mapa.get(entry.getKey());
            ob1.show();
            j++;
        } j=0;
        
    }
    
}

Program działa tak, jak chciałem, ale nie z bardzo rozumiem o co chodzi z tym Map.Entry (jednak rozumiem, czym jest pętla for each xd)? To są jakieś wyspecjalizowane metody związane z interfejsem Map? Może ktoś to szybko wytłumaczyć, bo znalazłem to rozwiązanie na tej stronie, ale nie jest tam nic wytłumaczone.

1
for(Map.Entry<Integer, Klasa1> entry : mapa.entrySet()){
            System.out.println("\nWartość klucza klasy nr "+j+" z mapy: "+entry.getKey());
            System.out.println("Wartość pól tej klasy: ");
            ob1 = mapa.get(entry.getKey());
            ob1.show();
            j++;
        }

Skoro używasz już foreacha dla entrySetu, to key oraz value otrzymujesz tak:

Integer key = entry.getKey(); Klasa1 value = entry.getValue();

nie musisz używasz map.get(key).

Co do tego entrySetu, jakbyś zajrzał w link, który Ci podesłałem wyżej, to wszystko byś tam znalazł :)

EDIT: nie bardzo rozumiem powyższe pytanie. W końcu wiesz co to foreach czy nie wiesz?

0

Dobra, to już chyba zostało mi ostatnie pytanie. xD

Zacząłem przeglądać ten kod i zauważyłem, że dwa razy powtarza się ten sam fragment kodu (pętla foreach do wypisywania Mapy). Po tym przypomniała mi się jedna z najważniejszych zasad programowania, którą poznałem gdy uczyłem się jeszcze programowania proceduralnego w C: "Jeżeli masz fragment kodu, który musisz użyć więcej niż jeden raz, nie kopiuj go, tylko wydziel do osobnej funkcji".
Jednak w Javie zamiast funkcji mamy klasy. Dopiero uczę się podstaw Javy i nie miałem jeszcze potrzeby podziału kodu na jakieś klasy i osobne pliki.
Spróbowałem to zrobić analogicznie, jak to robiłem z funkcjami w C i wyszło mi coś takiego:

Główny kod programu:

package mapa;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;


class Klasa1{
    int a; int b;
    
    Klasa1(){a=0; b=0;};
    Klasa1(int a, int b){this.a=a; this.b=b;};
    
    void show(){
        System.out.println("A = "+a+"; B = "+b);
    }
}


public class Mapa {

    
    public static void main(String[] args) {
        
        Map<Integer, Klasa1> mapa = new HashMap<>();
        int i=0; Integer a;
        Scanner scan = new Scanner(System.in);
        
        System.out.println("Podaj numery klucza trzech obiektów typu Klasa1: ");
        
        while(i<3){
           System.out.println("Klucz elementu "+(i+1)+": ");
           a = scan.nextInt(); scan.nextLine();
           mapa.put(a, new Klasa1(i,i+1));
           i++;
        } i=0; 
        Klasa1 ob1 = new Klasa1();
        
        System.out.println("W Mapie są następujące elementy:");
        
        Show_Map ob2 = new Show_Map(); //stworzenie obiektu klasy Show_Map
        ob2.meth(mapa); //wywołanie metody z klasy Show_Map, która wyświetla zawartość Mapy
        
        System.out.println("Jaki element chcesz usunąć z Mapy (podaj klucz): ");
        a = scan.nextInt(); scan.nextLine();
        mapa.remove(a);
        System.out.println("Usunięto element o kluczu = "+a);
        
        System.out.println("\nPonowne wyświetlenie zawartości Mapy, po usunięciu elementu: ");
        ob2.meth(mapa);
                
        
    }
    
}

Tutaj kod klasy, która jest odpowiedzialna za wypisanie zawartości Mapy:

package mapa;

import java.util.Map;

public class Show_Map{
    
    void meth(Map<Integer, Klasa1> mapa){
    
    Klasa1 ob1 = new Klasa1();
    int j=1;
        for(Map.Entry<Integer, Klasa1> entry : mapa.entrySet()){
            System.out.println("\nWartość klucza klasy nr "+j+" z mapy: "+entry.getKey());
            System.out.println("Wartość pól tej klasy: ");
            ob1 = mapa.get(entry.getKey());
            ob1.show();
            j++;
        } j=0;
    }
}

Może być coś takiego? Czy powinienem to zrobić inaczej? Tak jak pisałem, do tej pory w Javie nie dzieliłem kodu na inne klasy, więc wolę się o to zapytać, bo nie chcę łapać złych nawyków.

1

Jednak w Javie zamiast funkcji mamy klasy.

W javie mamy metody jako odpowiednik funkcji. Twoje void show() jest właśnie taką metodą.
Co do tego powtarzającego się kodu, tak masz rację.

Natomiast nie musisz tworzyć nowej klasy aby wrzucić tam tylko metodę do wyświetlania obiektów mapy.
Odniosę się jeszcze do tego Twojego show(). Poczytaj do czego jest metoda toString(), wtedy nadpisz ją w swojej klasie Klasa1.

0

Tak wiem, że metody są w programowaniu obiektowym odpowiednikiem funkcji, ale skoro nie musiałem tworzyć nowej klasy, to gdzie powinienem wrzucić tą metodę? Rozumiem, że do klasy "public class Mapa"? Czyli tej głównej klasy, w której jest cały kod?

Ale gdybym jednak się zdecydował na wrzucenie tej metody do innej klasy (bo np. byłaby bardzo duża, a w klasie Mapa miałbym już kilka funkcji i nie chciałbym "syfu" w kodzie), to dobrze to zrobiłem w powyższym przykładzie?

0

Niezbyt ładnie to zrobiłeś.

  1. Poczytaj o toString() i nadpisz tę metodę w Klasa1
  2. Wyrzuć te i oraz j z wyświetlania mapy, szczególnie, że zwykła mapa nie zachowuje kolejności obiektów do niej wrzuconych.
  3. Nie używaj języka polskiego, chyba że musisz.
  4. Wyświetlanie zawartości mapy można zrobić jedną linijką uzywając lambda expressions: map.forEach((key, value) -> System.out.println(key + ":" + value));

1 użytkowników online, w tym zalogowanych: 0, gości: 1