Это полностью противоречит Java-способу создания структурных объектов?
class SomeData1 {
public int x;
public int y;
}
Я вижу, что класс с аксессорами и мутаторами больше похож на Java.
class SomeData2 {
int getX();
void setX(int x);
int getY();
void setY(int y);
private int x;
private int y;
}
Класс из первого примера условно удобен.
// a function in a class
public int f(SomeData1 d) {
return (3 * d.x) / d.y;
}
Это не так удобно.
// a function in a class
public int f(SomeData2 d) {
return (3 * d.getX()) / d.getY();
}
Помните, что, хотя геттеры и сеттеры уродливы / многословны, это своего рода сердце Java. Это лаконичный язык. С другой стороны, вы НИКОГДА не должны вводить что-либо из этого, поскольку это то, что ваша IDE делает за вас. На динамическом языке вам нужно меньше печатать, но вы должны печатать (как правило, хотя IDE могут помочь).
По иронии судьбы, хотя OO имеет свои сильные стороны с точки зрения инкапсуляции, есть цена, которую нужно заплатить с точки зрения ЦП и хранилища. Сборщик мусора (почти полностью) устраняет необходимость беспокоиться о том, когда следует очистить ссылки на объекты. Текущая тенденция завершается полным кругом за счет использования C-подобных структур вне кучи. Это идеально подходит для решений типа кэширования, межпроцессного взаимодействия, более быстрых операций с интенсивным использованием памяти, более низкой производительности сборки мусора и даже выигрыша от более низкой производительности хранения для ваших наборов данных. Если вы знаете, что делаете, вы бы не задавали этот вопрос ... так что подумайте еще раз!
@ user924272: Re "Текущая тенденция идет полным ходом за счет использования C-подобных структур вне кучи". Что бы вы сделали на Java как ??? ИМХО, это та область, где Java показывает свой возраст ...
@ToolmakerSteve -Я вижу круг. Я не один. Такие компании, как Azul, стремятся к безостановочной сборке мусора. Ява старая. Истинный. Инженеры, которые обнаруживают слабость и что-то с ней делают, а не стонут? Они заслуживают уважения! +10 к Азулу от меня :-)




Я не вижу вреда, если вы знаете, что это всегда будет простая структура и что вы никогда не захотите привязать к ней поведение.
Если способ Java является способом объектно-ориентированного программирования, тогда да, создание класса с общедоступными полями нарушает принципы сокрытия информации, согласно которым объект должен управлять своим собственным внутренним состоянием. (Так как я не просто говорю вам жаргон, преимущество сокрытия информации заключается в том, что внутренняя работа класса скрыта за интерфейсом - скажем, вы хотели изменить механизм, с помощью которого ваш структурный класс сохранил одно из своих полей, вам, вероятно, придется вернуться и изменить любые классы, которые используют этот класс ...)
Вы также не можете воспользоваться преимуществами поддержки классов, совместимых с именами JavaBean, что повредит, если вы решите, скажем, использовать класс на странице JavaServer, написанной с использованием языка выражений.
Статья JavaWorld Почему методы геттера и сеттера - зло также может быть интересна вам, когда вы подумаете о том, когда не следует реализовывать методы доступа и мутатора.
Если вы пишете небольшое решение и хотите минимизировать объем используемого кода, способ Java может быть неправильным - я думаю, это всегда зависит от вас и проблемы, которую вы пытаетесь решить.
+1 за ссылку на статью "Почему методы Getter и Setter плохи". Однако ваш ответ был бы более ясным, если бы вы указали, что ОБЕ общедоступные поля И общедоступные геттеры / сеттеры НЕ ЯВЛЯЮТСЯ способом Java: как объясняется в этой статье - по возможности не делайте ни того, ни другого. Вместо этого предоставьте клиентам методы, специфичные для того, что им нужно делать, вместо того, чтобы отражать внутреннее представление экземпляра. ОДНАКО, это на самом деле не решает задаваемый вопрос (какой использовать для простого случая "структуры"), на который лучше ответить developer.g, izb и Брайан.
Это часто обсуждаемая тема. Недостаток создания общедоступных полей в объектах заключается в том, что вы не можете управлять значениями, которые им задаются. В групповых проектах, где много программистов используют один и тот же код, важно избегать побочных эффектов. Кроме того, иногда лучше вернуть копию объекта поля или как-то его преобразовать и т. д. Вы можете смоделировать такие методы в своих тестах. Если вы создадите новый класс, вы можете увидеть не все возможные действия. Это похоже на защитное программирование - когда-нибудь геттеры и сеттеры могут оказаться полезными, и их создание / использование не требует больших затрат. Так что иногда они полезны.
На практике у большинства полей есть простые геттеры и сеттеры. Возможное решение могло бы выглядеть так:
public property String foo;
a->Foo = b->Foo;
Обновление: маловероятно, что поддержка свойств будет добавлена в Java 7 или, возможно, когда-либо. Другие языки JVM, такие как Groovy, Scala и т. д., Теперь поддерживают эту функцию. - Алекс Миллер
Это очень плохо, мне нравятся свойства в стиле C# (похоже на то, о чем вы говорите)
Так что используйте перегрузку ... private int _x; public void x (int value) {_x = value; } public int x () {return _x; }
Я предпочитаю использовать =, что, на мой взгляд, делает код чище.
@Gordon: Вы даже можете опустить _ в имени переменной, потому что x и x() - это две совершенно разные вещи в Java. Так что public void x(int value) { x = value; } подойдет.
@ T-Bull: То, что у вас МОЖЕТ быть два x, это разные вещи, не делает это хорошей идеей. ИМХО, это плохое предложение, так как это может ввести в заблуждение читателей. Основной принцип: не заставляйте читателя переусердствовать; сделайте очевидным то, что вы говорите - используйте разные имена для разных сущностей. Даже если разница заключается только в добавлении подчеркивания. Не полагайтесь на окружающие знаки препинания, чтобы различать объекты.
@ToolmakerSteve: «Это может привести к путанице» - это самый распространенный и до сих пор самый слабый аргумент, когда дело доходит до защиты догмы кодирования (в отличие от стиля кодирования). Всегда найдется кто-то, кого МОЖЕТ запутать самые простые вещи. Вы всегда найдете кого-то, кто будет жаловаться на то, что он сделал ошибку после того, как не спал и кодировал полнедели или около того, а затем обвинял вводящий в заблуждение стиль кодирования. Я не позволяю этому считаться. Этот стиль действителен, очевиден и сохраняет пространство имен в чистоте. Кроме того, здесь нет разных сущностей, есть / one / entity и какой-то шаблонный код вокруг него.
public final String s; must be set in a constructor, where you have absolute control over it.
Это вопрос об объектно-ориентированном дизайне, а не о языке Java. Как правило, рекомендуется скрывать типы данных внутри класса и предоставлять только те методы, которые являются частью API класса. Если вы раскрываете внутренние типы данных, вы никогда не сможете их изменить в будущем. Если вы их скрываете, ваша единственная обязанность перед пользователем - это возвращаемый метод и типы аргументов.
Кстати, структура, которую вы даете в качестве примера, уже существует в библиотеке базовых классов Java как java.awt.Point. Он имеет x и y как общедоступные поля, Убедитесь сами.
Если вы знаете, что делаете, и другие в вашей команде знают об этом, то вполне нормально иметь общедоступные поля. Но вы не должны полагаться на это, потому что они могут вызвать головную боль, как в случае ошибок, связанных с разработчиками, использующими объекты, как если бы они были выделенными в стеке структурами (объекты java всегда отправляются в методы как ссылки, а не как копии).
+1 Хорошее упоминание о проблеме - способ, которым результат все еще НЕ похож на структуру C. Однако проблема, которую вы поднимаете о том, что объекты java всегда находятся по ссылке, не улучшается путем создания установщика вместо наличия общедоступного записываемого поля (что является сутью вопроса OP - какое представление использовать). Скорее, это аргумент в пользу НИЧЕГО. Это аргумент в пользу НЕПРЕРЫВНОСТИ. Это можно сделать либо как поле public final, как в ответе Брайана, либо с помощью общедоступного получателя, но без общедоступного установщика. То есть, использовать ли вы поля или методы доступа, не имеет значения.
Правильно руководствуйтесь здравым смыслом. Если у вас есть что-то вроде:
public class ScreenCoord2D{
public int x;
public int y;
}
Тогда нет смысла оборачивать их геттерами и сеттерами. Вы никогда не собираетесь хранить координаты x, y в целых пикселях другим способом. Геттеры и сеттеры вас только замедлят.
С другой стороны, с:
public class BankAccount{
public int balance;
}
Возможно, вы захотите изменить способ расчета баланса в какой-то момент в будущем. Это действительно должно использовать геттеры и сеттеры.
Всегда предпочтительно знать Почему, что вы применяете хорошую практику, чтобы знать, когда можно нарушить правила.
Я согласен с этим ответом и говорю, что вы можете создать класс с общедоступными полями, если поля не зависят друг от друга смелый. т.е. одно поле не зависит от другого. Это может быть весьма полезно во многих случаях для множественных значений, возвращаемых функцией, или для полярных совпадений. {angle, length}, которые идут вместе, но никак не зависят друг от друга.
@SpacenJasset: К вашему сведению, я не понимаю, как ваши примеры (несколько возвращаемых значений; полярные координаты) имеют какое-либо отношение к тому, использовать ли общедоступные поля или геттеры / сеттеры. В случае нескольких возвращаемых значений это может даже быть контрпродуктивным, потому что, возможно, вызывающий должен ПОЛУЧАТЬ только возвращаемые значения, что свидетельствует в пользу общедоступных геттеров и частных сеттеров (неизменяемых). Это также может быть верно для возврата полярных координат из объекта (x, y) - рассмотрите НАКОПИТЕЛЬНЫЕ математические ошибки, поскольку изменения отдельных компонентов полярных координат преобразуются обратно в (x, y).
@SpacenJasset: Но я согласен с вашим принципом.
У вас есть действительная точка, но мне кажется, что пиксели - это плохой пример, поскольку убедитесь, что пиксель находится в окне (просто пример) является что-то, что кто-то может сделать, и, кроме того, разрешение кому-то установить пиксель на (-5, -5) может не быть хорошей идеей. :-)
Re: аку, изб, Джон Топли ...
Остерегайтесь проблем с изменчивостью ...
Может показаться разумным опустить геттеры / сеттеры. На самом деле в некоторых случаях это может быть нормально. Настоящая проблема с предложенным шаблоном, показанным здесь, - это изменчивость.
Проблема заключается в том, что вы передаете ссылку на объект, содержащую неокончательные общедоступные поля. Все, что связано с этой ссылкой, может изменять эти поля. У вас больше нет контроля над состоянием этого объекта. (Подумайте, что бы произошло, если бы строки были изменяемыми.)
Плохо, когда этот объект является важной частью внутреннего состояния другого, вы только что раскрыли внутреннюю реализацию. Чтобы предотвратить это, вместо этого необходимо вернуть копию объекта. Это работает, но может вызвать огромную нагрузку на сборщик мусора из-за множества созданных одноразовых копий.
Если у вас есть общедоступные поля, подумайте о том, чтобы сделать класс доступным только для чтения. Добавьте поля в качестве параметров в конструктор и пометьте поля как окончательные. В противном случае убедитесь, что вы не раскрываете внутреннее состояние, и если вам нужно создать новые экземпляры для возвращаемого значения, убедитесь, что оно не будет вызываться чрезмерно.
См .: «Эффективная Java» Джошуа Блоха - Пункт № 13: Поддерживайте неизменность.
PS: Также имейте в виду, что все JVM в наши дни будут оптимизировать getMethod, если это возможно, в результате чего будет всего одна инструкция чтения поля.
Как геттер / сеттер решает эту проблему. У вас еще есть ссылка, у вас нет синхронизации с операциями. Геттеры / сеттеры сами по себе не обеспечивают защиту.
При необходимости геттеры и сеттеры могут обеспечить синхронизацию. Вы также ожидаете, что геттеры и сеттеры будут делать гораздо больше, чем они были указаны. Независимо от этого проблема синхронизации все равно остаётся.
Чтобы решить проблемы изменчивости, вы можете объявить x и y окончательными. Например:
class Data {
public final int x;
public final int y;
public Data( int x, int y){
this.x = x;
this.y = y;
}
}
Вызывающий код, который пытается выполнить запись в эти поля, получит ошибку времени компиляции «поле x объявлено окончательным; не может быть назначено».
В этом случае клиентский код может иметь удобство "короткой руки", которое вы описали в своем сообщении.
public class DataTest {
public DataTest() {
Data data1 = new Data(1, 5);
Data data2 = new Data(2, 4);
System.out.println(f(data1));
System.out.println(f(data2));
}
public int f(Data d) {
return (3 * d.x) / d.y;
}
public static void main(String[] args) {
DataTest dataTest = new DataTest();
}
}
Спасибо - ответ, который полезен и краток. Показывает, как использовать синтаксис поля, когда не требуется изменчивость.
@ToolmakerSteve - спасибо за отзыв - очень признателен.
Я попытался использовать конечные экземпляры конечного класса с конечными полями в качестве «экземпляров» структуры, но в выражении case, относящемся к такому полю экземпляра, я получил Case expressions must be constant expressions. как это обойтись? что здесь за идиоматическое понятие?
Поля final по-прежнему являются ссылками на объекты, которые не являются константами, поскольку они будут инициализированы при первом использовании класса. Компилятор не может знать «значение» объектных ссылок. При компиляции необходимо знать константы.
Проблема с использованием доступа к общедоступным полям такая же, как и при использовании нового вместо фабричного метода - если вы передумаете позже, все существующие вызывающие объекты будут сломаны. Итак, с точки зрения эволюции API, обычно рекомендуется укусить пулю и использовать геттеры / сеттеры.
Одно место, где я иду другим путем, - это когда вы строго контролируете доступ к классу, например, во внутреннем статическом классе, используемом в качестве внутренней структуры данных. В этом случае было бы гораздо проще использовать доступ к полю.
Между прочим, по утверждению e-bartek, весьма маловероятно, что, IMO, поддержка свойств будет добавлена в Java 7.
Это правда, но если вы используете Java, это не проблема, так как вы можете реорганизовать всю базу кода одним щелчком мыши (Eclipse, Netbeans, возможно, VIM и Emacs). Если вы выбрали одного из его динамических друзей, например Groovy, даже простая инкапсуляция может потребовать от вас исправления в течение нескольких часов или дней. К счастью, у вас есть тестовые примеры, которые проинформируют вас ... сколько еще кода вам нужно исправить.
Вы, конечно, предполагаете, что все пользователи - в вашей кодовой базе, но, конечно, часто это не так. Часто даже по разным нетехническим причинам невозможно изменить код, который может быть в вашей собственной кодовой базе.
Я часто использую этот шаблон при создании частных внутренних классов, чтобы упростить свой код, но я бы не рекомендовал раскрывать такие объекты в общедоступном API. В общем, чем чаще вы можете делать объекты в своем общедоступном API неизменяемыми, тем лучше, и невозможно создать свой «структурно-подобный» объект неизменяемым образом.
Кстати, даже если бы я писал этот объект как частный внутренний класс, я бы все равно предоставил конструктор для упрощения кода для инициализации объекта. Необходимость иметь 3 строки кода для получения пригодного к использованию объекта, когда он будет использоваться, - это просто беспорядок.
Вы можете создать простой класс с общедоступными полями и без методов в Java, но он по-прежнему является классом и по-прежнему обрабатывается синтаксически и с точки зрения распределения памяти, как класс. Невозможно по-настоящему воспроизвести структуры в Java.
Иногда я использую такой класс, когда мне нужно вернуть несколько значений из метода. Конечно, такой объект недолговечный и с очень ограниченной видимостью, так что все должно быть в порядке.
Я пробовал это в нескольких проектах, исходя из теории, что геттеры и сеттеры загромождают код семантически бессмысленным мусором, и что другие языки, похоже, отлично справляются с скрытием данных на основе соглашений или разделением обязанностей (например, python).
Как уже отмечалось выше, есть 2 проблемы, с которыми вы сталкиваетесь, и на самом деле они не решаемы:
И это в лучшем случае полностью работать в автономном частном проекте. Как только вы экспортируете все это в общедоступную библиотеку, эти проблемы станут еще больше.
Java очень многословен, и это очень соблазнительно. Не делай этого.
Отличное обсуждение проблем выхода на общественные поля. Несомненный недостаток Java, который меня раздражает, когда мне приходится переключаться обратно на Java с C# (чему я здесь научился на неудобствах Java).
В этом типе кода нет ничего плохого, при условии, что автор знает представляет собой структуры (или шаттлы данных), а не объекты. Многие разработчики Java не могут отличить хорошо сформированный объект (не только подкласс java.lang.Object, но и объект истинный в определенном домене) и ананас. Следовательно, они в конечном итоге пишут структуры, когда им нужны объекты, и наоборот.
ананас смешит меня :)
Однако этот ответ ничего не говорит о том, в чем разница. Треп с неквалифицированными разработчиками не помогает этим разработчикам знать, когда создавать структуру, а когда - класс.
Он ничего не говорит о различии, потому что их автор знает о различии (он знает, что такое структуроподобная сущность). Автор спрашивает, уместно ли использование структур в объектно-ориентированном языке, и я отвечаю «да» (в зависимости от предметной области). Если бы вопрос был о том, что делает объект реальным объектом предметной области, тогда у вас была бы нога, чтобы стоять в своем аргумент.
Более того, единственный неквалифицированный разработчик, который не должен знать разницы, - это тот, кто еще учится в школе. Это чрезвычайно важно, например, знание разницы между связанным списком и хеш-таблицей. Если человек получает 4-летнюю степень в области программного обеспечения, не зная, что такое настоящий объект, то либо этот человек не подходит для этой карьеры, либо он / она должны вернуться в школу и потребовать возмещения. Я серьезно.
Но чтобы удовлетворить вашу жалобу, я дам ответ (который не имеет ничего общего с исходным вопросом и заслуживает отдельной темы). Объекты имеют поведение и инкапсулируют состояние. Структуры нет. Объекты - это конечные автоматы. Структуры предназначены только для агрегирования данных. Если люди хотят получить более подробный ответ, они могут создать новый вопрос, где мы сможем уточнить его, сколько душе угодно.
Как и в большинстве случаев, есть общее правило, а затем есть определенные обстоятельства. Если вы создаете закрытое захваченное приложение, чтобы знать, как будет использоваться данный объект, вы можете проявить больше свободы в пользу видимости и / или эффективности. Если вы разрабатываете класс, который будет публично использоваться другими людьми, не зависящими от вас, тогда склоняйтесь к модели получателя / установщика. Как и во всем, просто руководствуйтесь здравым смыслом. Часто бывает нормально провести начальный раунд с пабликами, а потом поменять их на геттеры / сеттеры.
Похоже, что многие люди, занимающиеся Java, не знакомы с Руководством по кодированию Sun Java. которые говорят, что вполне уместно использовать общедоступную переменную экземпляра, когда класс по сути, «структура», если Java поддерживает «структуру» (когда нет поведения).
Люди склонны думать, что геттеры и сеттеры - это способ Java, как будто они лежат в основе Java. Это не так. Если вы следуете Sun Java Рекомендации по кодированию с использованием переменных публичного экземпляра в соответствующих ситуациях, вы на самом деле пишете лучший код, чем загромождаете его ненужными геттерами и сеттерами.
Соглашения о коде Java с 1999 г. и без изменений.
10.1 Предоставление доступа к переменным экземпляра и класса
Не делайте никаких экземпляров или переменных класса общедоступными без уважительной причины. Часто переменные экземпляра не нужно явно устанавливать или получать - часто это происходит как побочный эффект вызовов методов.
Одним из примеров подходящих общедоступных переменных экземпляра является случай, когда класс по сути является структурой данных, не имеющей поведения. Другими словами, если вы использовали бы структуру вместо класса (если Java поддерживала структуру), тогда уместно сделать переменные экземпляра класса общедоступными..
http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177
http://en.wikipedia.org/wiki/Plain_old_data_structure
http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28
+1 За действительно авторитетный источник. Любой другой ответ - это люди, выдвигающие свои мнения, как будто они являются фактами.
Существует спецификация Java Beans, которая является отраслевым стандартом для доступа к свойствам с использованием методов get и set ... см. en.wikipedia.org/wiki/JavaBeans для обзора.
@ user924272: Как эта спецификация Java Beans имеет отношение к этому ответу, в котором обсуждается, когда уместно использовать «общедоступные переменные экземпляра»? Если бы спецификация была стандартным способом автоматического превращения переменных экземпляра в свойства, например, C#, это могло бы быть актуально. Но это ведь не так? Он просто указывает наименование шаблонных методов получения и установки, которые необходимо создать для создания такого сопоставления.
@ToolmakerSteve. Это вопрос java. Кроме того, вопрос ускользает от общей проблемы, когда существует спецификация. С точки зрения старой школы, гораздо проще отлаживать мутации полей, когда есть стандартный способ сделать это - установить точку останова в установщике. Это, вероятно, устарело с современными отладчиками, но я вынужден осуждать классы, которые напрямую «пробивают» объекты ... хотя это нормально для небольших приложений, это настоящая головная боль для больших приложений и крупных организаций.
Это должен быть принятый ответ
Аспектно-ориентированное программирование позволяет вам перехватывать назначения или выборки и присоединять к ним логику перехвата, что, как я предлагаю, является правильным способом решения проблемы. (Вопрос о том, должны ли они быть общедоступными, защищенными или защищенными пакетами, ортогонален.)
Таким образом, вы начинаете с неперехваченных полей с правильным квалификатором доступа. По мере роста требований к программе вы присоединяете логику, возможно, для проверки, создания копии возвращаемого объекта и т. д.
Философия геттера / сеттера требует затрат в большом количестве простых случаев, когда они не нужны.
Является ли аспектный стиль более чистым или нет, в некоторой степени качественным. Мне было бы легко видеть только переменные в классе и отдельно рассматривать логику. Фактически, смысл существования Apect-ориентированного программирования заключается в том, что многие проблемы являются сквозными, и разделение их в теле самого класса не идеально (например, ведение журнала - если вы хотите регистрировать все, что Java хочет, чтобы вы напишите целую кучу геттеров и синхронизируйте их, но AspectJ позволяет вам однострочно).
Проблема IDE - отвлекающий маневр. Это не столько набор текста, сколько чтение и визуальное загрязнение, возникающее из-за get / sets.
Аннотации на первый взгляд кажутся похожими на аспектно-ориентированное программирование, однако они требуют, чтобы вы исчерпывающе перечислили pointcut, прикрепив аннотации, в отличие от краткой спецификации pointcut в стиле подстановочных знаков в AspectJ.
Я надеюсь, что знание AspectJ предотвратит преждевременное использование динамических языков.
У AOJ есть обратная сторона - непрозрачная обработка и придание веса стадии прекомпиляции. Новичку в проекте может быть очень сложно понять, что делает код, а также как вносить изменения. Я говорю об этом, исходя из опыта проекта 5K SLOC, который казался на несколько X больше из-за сложности определения того, что на самом деле происходит.
Здесь я создаю программу для ввода имени и возраста 5 разных людей и выполняю сортировку (по возрасту). Я использовал класс, который действует как структура (например, язык программирования C), и основной класс для выполнения всей операции. Ниже я представляю код ...
import java.io.*;
class NameList {
String name;
int age;
}
class StructNameAge {
public static void main(String [] args) throws IOException {
NameList nl[]=new NameList[5]; // Create new radix of the structure NameList into 'nl' object
NameList temp=new NameList(); // Create a temporary object of the structure
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
/* Enter data into each radix of 'nl' object */
for(int i=0; i<5; i++) {
nl[i]=new NameList(); // Assign the structure into each radix
System.out.print("Name: ");
nl[i].name=br.readLine();
System.out.print("Age: ");
nl[i].age=Integer.parseInt(br.readLine());
System.out.println();
}
/* Perform the sort (Selection Sort Method) */
for(int i=0; i<4; i++) {
for(int j=i+1; j<5; j++) {
if (nl[i].age>nl[j].age) {
temp=nl[i];
nl[i]=nl[j];
nl[j]=temp;
}
}
}
/* Print each radix stored in 'nl' object */
for(int i=0; i<5; i++)
System.out.println(nl[i].name+" ("+nl[i].age+")");
}
}
Приведенный выше код не содержит ошибок и протестирован ... Просто скопируйте и вставьте его в свою среду IDE и ... Знаете и что ??? :)
Очень-очень старый вопрос, но позвольте мне сделать еще один небольшой вклад. В Java 8 появились лямбда-выражения и ссылки на методы. Лямбда-выражения могут быть простыми ссылками на методы и не объявлять «истинное» тело. Но вы не можете «преобразовать» поле в ссылку на метод. Таким образом
stream.mapToInt(SomeData1::x)
не законно, но
stream.mapToInt(SomeData2::getX)
является.
В этом случае вы можете использовать data -> data.x, что все еще разумно.
publicНе используйте поля public, если вы действительно хотите обернуть внутреннее поведение класса. Возьмем, к примеру, java.io.BufferedReader. В нем есть следующее поле:
private boolean skipLF = false; // If the next character is a line feed, skip it
skipLF читается и записывается всеми методами чтения. Что, если внешний класс, работающий в отдельном потоке, злонамеренно изменил состояние skipLF в середине чтения? BufferedReader определенно выйдет из строя.
publicВозьмем, к примеру, этот класс Point:
class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return this.x;
}
public double getY() {
return this.y;
}
public void setX(double x) {
this.x = x;
}
public void setY(double y) {
this.y = y;
}
}
Это сделало бы расчет расстояния между двумя точками очень болезненным.
Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.getX() - a.getX(), 2) + Math.pow(b.getY() - a.getY(), 2));
Класс не имеет другого поведения, кроме простых методов получения и установки. Допустимо использовать общедоступные поля, когда класс представляет только структуру данных и не имеет, и никогда не будет иметь поведения (тонкие геттеры и сеттеры - это нет, рассматриваемое здесь поведением). Лучше записать это можно так:
class Point {
public double x;
public double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
}
Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
Чистый!
Но помните: не только ваш класс должен отсутствовать в поведении, но он также должен иметь причину нет для поведения в будущем.
(Это именно то, что описывает этот ответ. Процитируем «Соглашения о коде для языка программирования Java: 10. Практики программирования»:
One example of appropriate public instance variables is the case where the class is essentially a data structure, with no behavior. In other words, if you would have used a
structinstead of a class (if Java supportedstruct), then it's appropriate to make the class's instance variables public.
Таким образом, официальная документация также принимает эту практику.)
Кроме того, если вы абсолютно уверены, что члены вышеуказанного класса Point должны быть неизменными, вы можете добавить ключевое слово final, чтобы обеспечить его соблюдение:
public final double x;
public final double y;
Вместо общедоступных изменяемых полей рассмотрите либо общедоступные неизменяемые поля, либо изменяемые поля локального пакета. Либо лучше ИМХО.