Несмотря на то, что есть несколько хороших ответов, особенно , написанных пеплом , они касаются конкретного вопроса, поднятого в заголовке о возврате двух значений.Однако вы подняли еще два вопроса, которые показывают большую проблему.
Преждевременная оптимизация
Разве это не крайне неэффективно, имея полный класс только для этой маленькой цели?
Всегда используйте сначала clean design .Не создавайте первоначальный дизайн из-за мнимой возможной проблемы производительности или чрезмерного беспокойства по поводу эффективности.В настоящее время процессоры выполняют от двух до четырех миллиардов инструкций в секунду, поэтому мы можем позволить себе небольшую неэффективность.Делать код понятным, легко читаемым, легко отлаживаемым и легко модифицируемым почти всегда важнее эффективности.
Кроме того, программисты любого уровня, как известно, плохо предсказывают производительность и узкие места.Не пачкайте свой дизайн компромиссами, пока у вас не появится проверенное узкое горлышко некоторой значимости.
Что если бы я хотел посчитать другую пару значений?Должен ли я создать еще один совершенно новый класс?
Этот вопрос указывает на неуклюжость ваших попыток объединить запросы, которые должны быть отдельными.
Давайте напишем некоторый код.Во-первых, класс Person
.
Enum
Обратите внимание, что мы вложили два перечисления, Gender
& Maturity
.Если вы не знакомы, см. Oracle Tutorial .Средство enum в Java на намного более полезно, гибко и мощно, чем в других языках.Использование строк в качестве флагов значений неуклюже и подвержено ошибкам.Компилятор не может помочь вам с опечатками.Напротив, компилятор может помочь вам с перечислениями, добавив type-safety в ваш код, обеспечивая при этом допустимые значения.
Преимущества использования перечислений: очень мало используемой памяти и очень быстрое выполнение.
package work.basil.example;
import java.util.Objects;
import java.util.UUID;
public class Person
{
public enum Gender
{
FEMALE, MALE
}
public enum Maturity
{
ADULT, CHILD
}
// Members
private UUID id;
private Gender gender;
private Maturity maturity;
// Constructor
public Person ( UUID id , Gender gender , Maturity maturity )
{
Objects.requireNonNull ( id );
Objects.requireNonNull ( gender );
Objects.requireNonNull ( maturity );
this.id = id;
this.gender = gender;
this.maturity = maturity;
}
// Accessors
public UUID getId ( )
{
return id;
}
public Gender getGender ( )
{
return gender;
}
public Maturity getMaturity ( )
{
return maturity;
}
// Object overrides
@Override
public String toString ( )
{
return "Person{" +
"id=" + id +
", gender=" + gender +
", maturity=" + maturity +
'}';
}
@Override
public boolean equals ( Object o )
{
if ( this == o ) return true;
if ( o == null || getClass () != o.getClass () ) return false;
Person person = ( Person ) o;
return id.equals ( person.id );
}
@Override
public int hashCode ( )
{
return Objects.hash ( this.id );
}
}
Напишите метод countPeople
, который принимает List
из Person
объектов, вместе с вашей парой критериев (пол и зрелость).
Мы можем передать любую комбинацию пола и зрелости.Этот дизайн продолжает работать, даже когда вы добавляете значения к вашим перечислениям, таким как Gender.UNKNOWN
и Maturity.ADOLESCENT
.
private Integer countPeople ( List < Person > people , Person.Gender gender , Person.Maturity maturity )
{
Objects.requireNonNull ( people );
Objects.requireNonNull ( gender );
Objects.requireNonNull ( maturity );
Integer count = 0;
for ( Person person : people )
{
if ( ( person.getGender ().equals( gender ) ) && ( person.getMaturity ().equals( maturity ) ) )
{
count = ( count + 1 );
}
}
return count;
}
И напишите некоторый код для осуществления этого подсчета кода.
Синтаксис List.of
является новым в Java 9 и более поздних версиях, создавая неизменяемый объект List
неопределенного конкретногокласс в одну простую строку кода.
List < Person > people = List.of (
new Person ( UUID.randomUUID () , Person.Gender.FEMALE , Person.Maturity.CHILD ) ,
new Person ( UUID.randomUUID () , Person.Gender.FEMALE , Person.Maturity.ADULT ) ,
new Person ( UUID.randomUUID () , Person.Gender.MALE , Person.Maturity.ADULT ) ,
new Person ( UUID.randomUUID () , Person.Gender.FEMALE , Person.Maturity.CHILD ) ,
new Person ( UUID.randomUUID () , Person.Gender.MALE , Person.Maturity.ADULT ) ,
new Person ( UUID.randomUUID () , Person.Gender.MALE , Person.Maturity.CHILD ) ,
new Person ( UUID.randomUUID () , Person.Gender.FEMALE , Person.Maturity.ADULT )
);
Integer women = this.countPeople ( people , Person.Gender.FEMALE , Person.Maturity.ADULT );
Integer boys = this.countPeople ( people , Person.Gender.MALE , Person.Maturity.CHILD );
Report.
System.out.println ( "people = " + people );
System.out.println ( "women = " + women );
System.out.println ( "boys = " + boys );
people = [Person {id = 1ac225e6-f21c-49f5-82d5-8e0f289f16e0, пол =ЖЕНЩИНА, зрелость = РЕБЕНОК, Лицо {id = 333828cc-48e6-4d0c-9937-66f3168445bd, пол = ЖЕНЩИНА, зрелость = ВЗРОСЛЫЙ}, Лицо {id = 4d37bc08-1e1f-4806-8d84-dc314b6b2cd8, пол = МУЖ, зрелость =ADULT}, Person {id = 0cd2a38a-5b01-4091-9cb2-c0284739aa70, пол = FEMALE, зрелость = РЕБЕНОК), Person {id = 36d9af87-3cbb-44bc-bf03-67df45a5d8c8, пол = MALE, зрелость = ADULT}, Person{id = 2fef944a-79c9-4b29-9191-4bc694b58a4d, пол = MALE, зрелость = РЕБЕНОК), Person {id = ffc8f355-9a4b-47c3-8092-f64b6da87483, пол = FEMALE, зрелость = ADULT}]
women = 2
boys = 1
Streams
Мы могли бы придумать и использовать вместо этого потоки for
loсоч.Не обязательно лучше в этом случае, но веселее.
Мы собираемся позвонить Stream::count
.Это возвращает long, поэтому измените наше использование 32-битного целого числа на 64-bit long.Или же вы можете привести long к целому числу.
Вызов List::stream
генерирует поток объектов Person
, содержащихся в списке.
A Predicate
объект содержит наш тест на пол и наш тест на зрелость.Вызов Stream::filter
применяет предикат для выбора объектов.Они подсчитываются по телефону Stream::count
.
private Long countPeople ( List < Person > people , Person.Gender gender , Person.Maturity maturity )
{
Objects.requireNonNull ( people );
Objects.requireNonNull ( gender );
Objects.requireNonNull ( maturity );
Predicate < Person > predicate = ( Person person ) -> ( person.getGender ().equals ( gender ) && person.getMaturity ().equals ( maturity ) );
Long count = people.stream ().filter ( predicate ).count ();
return count;
}
Совет: Производительность с очень большими списками людей может быть лучше, если вы перейдете к следующему шагу, чтобы распараллелить поток .
Базы данных
Если эти данные поступают из базы данных, вы должны выполнять эту работу в этой базе данных, а не на стороне Java.Механизмы баз данных, такие как Postgres , оптимизированы для * , чтобы выполнять только такие операции выбора, сравнения, сортировки и подсчета.