Jak zwrócić 2 wartości z metody Java?

179

Próbuję zwrócić 2 wartości z metody Java, ale dostaję te błędy. Oto mój kod:

// Method code
public static int something(){
    int number1 = 1;
    int number2 = 2;

    return number1, number2;
}

// Main method code
public static void main(String[] args) {
    something();
    System.out.println(number1 + number2);
}

Błąd:

Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - missing return statement
    at assignment.Main.something(Main.java:86)
    at assignment.Main.main(Main.java:53)

Wynik Java: 1

javaLearner.java
źródło
1
Czy ten duplikat powinien być odwrotny? Odpowiedź tutaj wydaje się lepsza.
J Richard Snape,

Odpowiedzi:

239

Zamiast zwracać tablicę zawierającą dwie wartości lub używać wartości ogólnej Pair klasy , rozważ utworzenie klasy reprezentującej wynik, który chcesz zwrócić, i zwróć instancję tej klasy. Nadaj klasie sensowne imię. Zaletami tego podejścia w porównaniu z użyciem macierzy jest bezpieczeństwo typu i znacznie ułatwi to zrozumienie programu.

Uwaga: PairKlasa ogólna , jak zaproponowano w niektórych innych odpowiedziach tutaj, zapewnia również bezpieczeństwo pisania, ale nie przekazuje tego, co reprezentuje wynik.

Przykład (który nie używa naprawdę znaczących nazw):

final class MyResult {
    private final int first;
    private final int second;

    public MyResult(int first, int second) {
        this.first = first;
        this.second = second;
    }

    public int getFirst() {
        return first;
    }

    public int getSecond() {
        return second;
    }
}

// ...

public static MyResult something() {
    int number1 = 1;
    int number2 = 2;

    return new MyResult(number1, number2);
}

public static void main(String[] args) {
    MyResult result = something();
    System.out.println(result.getFirst() + result.getSecond());
}
Jesper
źródło
1
To byłaby moja preferowana trasa - przypuszczalnie para liczb ma jakieś znaczenie i byłoby miło, gdyby reprezentował to typ zwracany.
Armand
3
Możesz użyć SimpleEntry <type_of_value_1, type_of_value_2> z java.util.AbstractMap.SimpleEntry i użyć go z getKey (), aby uzyskać obiekt 1 i getValue (), aby uzyskać obiekt 2
Crystalonics
45
Bardzo mocno czuję, że Java powinna umożliwiać zwracanie wielu wartości. Byłoby to szybsze (utworzono mniej obiektów) i nie wymagałoby dodatkowych klas (nadęty kod) za każdym razem, gdy chcesz zrobić coś nieco innego. Nie widzę żadnych wad, może ktoś może mnie oświecić?
Chris Seline,
Jest to tylko obejście zadanego pytania, które nadal oznacza „jak zwrócić 2 wartości z metody, tak jak robimy to w Pythonie”.
Anum Sheraz,
4
@AnumSheraz Odpowiedź na „jak ... tak jak w Pythonie” brzmi: nie, bo Java nie ma takiej funkcji językowej ...
Jesper
73

Java nie obsługuje zwrotów o wielu wartościach. Zwraca tablicę wartości.

// Function code
public static int[] something(){
    int number1 = 1;
    int number2 = 2;
    return new int[] {number1, number2};
}

// Main class code
public static void main(String[] args) {
  int result[] = something();
  System.out.println(result[0] + result[1]);
}
Matt
źródło
7
Jest to prawie zawsze niewłaściwa rzecz, szczególnie jeśli typy dwóch wartości wyników są różne.
Kevin Sitze
7
@BarAkiva, przyczyną tego jest błąd, ponieważ straciłeś bezpieczeństwo typu. Jeśli zwracasz wartości jednorodnego typu, zawsze powinieneś preferować Listę niż tablicę. W szczególności, jeśli masz do czynienia z wartościami ogólnymi, wówczas List <T> jest zawsze preferowana jako wartość zwracana nad T [], ponieważ zawsze możesz zbudować List na typie ogólnym, ale nigdy na tablicy; nie możesz tego zrobić: „new T [length];” Podejście do tworzenia klasy Pary, jak wskazano tutaj dla różnych typów, jest lepszą opcją dla typów heterogenicznych.
Kevin Sitze,
41

Możesz zaimplementować ogólny, Pairjeśli jesteś pewien, że musisz tylko zwrócić dwie wartości:

public class Pair<U, V> {

 /**
     * The first element of this <code>Pair</code>
     */
    private U first;

    /**
     * The second element of this <code>Pair</code>
     */
    private V second;

    /**
     * Constructs a new <code>Pair</code> with the given values.
     * 
     * @param first  the first element
     * @param second the second element
     */
    public Pair(U first, V second) {

        this.first = first;
        this.second = second;
    }

//getter for first and second

a następnie niech metoda zwróci, że Pair:

public Pair<Object, Object> getSomePair();
Lars Andren
źródło
Jak wyglądałby zwrot tej metody?
Jwan622
Coś w stylu: pair = new Pair (thing1, thing2) .... zwróć parę;
Lars Andren
27

Możesz zwrócić tylko jedną wartość w Javie, więc najładniejszy sposób jest następujący:

return new Pair<Integer>(number1, number2);

Oto zaktualizowana wersja Twojego kodu:

public class Scratch
{
    // Function code
    public static Pair<Integer> something() {
        int number1 = 1;
        int number2 = 2;
        return new Pair<Integer>(number1, number2);
    }

    // Main class code
    public static void main(String[] args) {
        Pair<Integer> pair = something();
        System.out.println(pair.first() + pair.second());
    }
}

class Pair<T> {
    private final T m_first;
    private final T m_second;

    public Pair(T first, T second) {
        m_first = first;
        m_second = second;
    }

    public T first() {
        return m_first;
    }

    public T second() {
        return m_second;
    }
}
richj
źródło
8

Oto naprawdę proste i krótkie rozwiązanie z SimpleEntry:

AbstractMap.Entry<String, Float> myTwoCents=new AbstractMap.SimpleEntry<>("maximum possible performance reached" , 99.9f);

String question=myTwoCents.getKey();
Float answer=myTwoCents.getValue();

Używa tylko wbudowanych funkcji Java i ma tę zaletę, że zapewnia bezpieczeństwo.

Kod ninetyninepointnine
źródło
6

musisz użyć kolekcji, aby zwrócić więcej niż jedną zwracaną wartość

w twoim przypadku piszesz swój kod jako

public static List something(){
        List<Integer> list = new ArrayList<Integer>();
        int number1 = 1;
        int number2 = 2;
        list.add(number1);
        list.add(number2);
        return list;
    }

    // Main class code
    public static void main(String[] args) {
      something();
      List<Integer> numList = something();
    }
GuruKulki
źródło
4
public class Mulretun
{
    public String name;;
    public String location;
    public String[] getExample()
    {
        String ar[] = new String[2];
        ar[0]="siva";
        ar[1]="dallas";
        return ar; //returning two values at once
    }
    public static void main(String[] args)
    {
        Mulretun m=new Mulretun();
        String ar[] =m.getExample();
        int i;
        for(i=0;i<ar.length;i++)
        System.out.println("return values are: " + ar[i]);      

    }
}

o/p:
return values are: siva
return values are: dallas
siva
źródło
4

Użyj obiektu typu Para / Tuple, nawet nie musisz go tworzyć, jeśli zależysz od Apache commons-lang. Wystarczy użyć klasy Pair .

UserF40
źródło
Dlaczego nie jest to bardziej entuzjastyczne?
Rauni Lillemets
3

Jestem ciekawy, dlaczego nikt nie wymyślił bardziej eleganckiego rozwiązania zwrotnego. Zamiast więc używać typu zwracanego, używasz procedury przekazanej do metody jako argumentu. Poniższy przykład ma dwa przeciwstawne podejścia. Wiem, który z nich jest dla mnie bardziej elegancki. :-)

public class DiceExample {

    public interface Pair<T1, T2> {
        T1 getLeft();

        T2 getRight();
    }

    private Pair<Integer, Integer> rollDiceWithReturnType() {

        double dice1 = (Math.random() * 6);
        double dice2 = (Math.random() * 6);

        return new Pair<Integer, Integer>() {
            @Override
            public Integer getLeft() {
                return (int) Math.ceil(dice1);
            }

            @Override
            public Integer getRight() {
                return (int) Math.ceil(dice2);
            }
        };
    }

    @FunctionalInterface
    public interface ResultHandler {
        void handleDice(int ceil, int ceil2);
    }

    private void rollDiceWithResultHandler(ResultHandler resultHandler) {
        double dice1 = (Math.random() * 6);
        double dice2 = (Math.random() * 6);

        resultHandler.handleDice((int) Math.ceil(dice1), (int) Math.ceil(dice2));
    }

    public static void main(String[] args) {

        DiceExample object = new DiceExample();


        Pair<Integer, Integer> result = object.rollDiceWithReturnType();
        System.out.println("Dice 1: " + result.getLeft());
        System.out.println("Dice 2: " + result.getRight());

        object.rollDiceWithResultHandler((dice1, dice2) -> {
            System.out.println("Dice 1: " + dice1);
            System.out.println("Dice 2: " + dice2);
        });
    }
}
Steve O 1969
źródło
2

Nie musisz tworzyć własnej klasy, aby zwrócić dwie różne wartości. Wystarczy użyć HashMap w następujący sposób:

private HashMap<Toy, GameLevel> getToyAndLevelOfSpatial(Spatial spatial)
{
    Toy toyWithSpatial = firstValue;
    GameLevel levelToyFound = secondValue;

    HashMap<Toy,GameLevel> hm=new HashMap<>();
    hm.put(toyWithSpatial, levelToyFound);
    return hm;
}

private void findStuff()
{
    HashMap<Toy, GameLevel> hm = getToyAndLevelOfSpatial(spatial);
    Toy firstValue = hm.keySet().iterator().next();
    GameLevel secondValue = hm.get(firstValue);
}

Masz nawet zaletę bezpieczeństwa typu.

Kod ninetyninepointnine
źródło
2
Nie potrzebujesz nawet HashMap, wystarczy użyć SimpleEntry!
Xerus,
Dlaczego HashMap, mogę zapytać? To wygląda na dziwną strukturę danych do użycia tutaj.
Neil Chowdhury,
@Neil Chowdhury Nie ma innego powodu niż to, że jest to wygodnie wbudowana klasa przyjmująca dwa definiowalne parametry. Jak zauważył Xerus, AbstractMap.SimpleEntry jest tutaj bardziej lekką opcją. Zobacz odpowiednią odpowiedź poniżej!
Kod ninetyninepointnine
2

Moim zdaniem najlepiej jest stworzyć nową klasę, której konstruktor jest potrzebną funkcją, np .:

public class pairReturn{
        //name your parameters:
        public int sth1;
        public double sth2;
        public pairReturn(int param){
            //place the code of your function, e.g.:
            sth1=param*5;
            sth2=param*10;
        }
    }

Następnie po prostu użyj konstruktora, tak jak przy użyciu funkcji:

pairReturn pR = new pairReturn(15);

i możesz użyć pR.sth1, pR.sth2 jako „2 wyników funkcji”

Jakub
źródło
1

Możesz również wysyłać zmienne obiekty jako parametry, jeśli użyjesz metod do ich modyfikacji, zostaną one zmodyfikowane po powrocie z funkcji. Nie będzie działać na takich rzeczach jak Float, ponieważ jest niezmienny.

public class HelloWorld{

     public static void main(String []args){
        HelloWorld world = new HelloWorld();

        world.run();
     }



    private class Dog
    {
       private String name;
       public void setName(String s)
       {
           name = s;
       }
       public String getName() { return name;}
       public Dog(String name)
       {
           setName(name);
       }
    }

    public void run()
    {
       Dog newDog = new Dog("John");
       nameThatDog(newDog);
       System.out.println(newDog.getName());
     }


     public void nameThatDog(Dog dog)
     {
         dog.setName("Rutger");
     }
}

Wynik jest następujący: Rutger

Andreas
źródło
1

Zwróć tablicę obiektów

private static Object[] f () 
{ 
     double x =1.0;  
     int y= 2 ;
     return new Object[]{Double.valueOf(x),Integer.valueOf(y)};  
}
MC
źródło
0

Po pierwsze, byłoby lepiej, gdyby Java miała krotki do zwracania wielu wartości.

Po drugie, koduj najprostszą możliwą Pairklasę lub użyj tablicy.

Ale jeśli zrobić potrzebę powrotu parę, za co pojęcie to oznacza (poczynając od jego nazwy pól, a następnie nazwa klasy) - i czy odgrywa to większej roli niż myślałeś, a jeśli to pomoże ogólny projekt, aby mieć wyraźna abstrakcja. Może to code hint...
Uwaga: Nie jestem dogmatycznie mówiąc, że będzie pomóc, ale tylko patrzeć, aby zobaczyć , czy to robi ... czy też nie.

hyperpallium
źródło
-7

i to w jaki sposób to zrobić w JS: return { objA, valueB }. Wiem, że to nie na temat, ale nie mogę powstrzymać się od pozostawienia tego komentarza po tym, jak zobaczyłem, jak zaimplementować całą nową klasę w Javie. JavaScript - przestań marnować swoje życie i zacznij pisać skrypty!

zavr
źródło