Статьи

Java SE 11: продвижение Java вперед

Вступление

В этой серии статей рассказывается, как, на мой взгляд, язык Java должен развиваться, чтобы оставаться основным языком выбора. В нем также представлены некоторые функции, иногда уже существующие на другом языке, которые я люблю, но которые не могут (или не должны быть) частью Java, по некоторым причинам, которые я объясню. Я бы очень хотел превратить некоторые из этих идей в JSR.

За последние 15 лет язык Java и JVM были значительно улучшены. JIT-компилятор, появление дженериков, автобокс, скоро (скрестив пальцы) лямбды… Все эти функции способствовали успеху Java. Но что дальше? Как сделать Java лучше?

Благодаря своему опыту, у меня была возможность работать с несколькими языками программирования. Это включает в себя C #, C / C ++, PHP, Javascript, Groovy, ActionScript 3, Scala и некоторые другие … Во многих из этих языков я обнаружил некоторые особенности, которые заставили меня сказать «это чертовски здорово!». Некоторые из этих функций не были применимы к Java (другая парадигма программирования, другое мышление), в то время как другие были полностью применимы. Также в некоторых из этих языков (в основном в PHP…) я видел вещи, которые заставляли меня говорить «О Боже! Это дерьмо! »… Но это другая история!

В каждой части этой серии я представлю одну особенность, которая не существует в Java, и объясню, почему она должна (или нет) быть в Java, возможные проблемы, с которыми нужно иметь дело, и т. Д…

Не стесняйтесь размещать идеи улучшения, даже самые безумные / нереальные! Я не претендую на идеальные решения, я просто пытаюсь открыть дискуссию.

Свойства доступа

В статье представлено, как, на мой взгляд, должен развиваться язык Java, чтобы он оставался лучшим выбором. В нем также представлены некоторые функции, иногда уже существующие на другом языке, которые я люблю, но которые не могут (или не должны быть) частью Java, по некоторым причинам, которые я объясню. Я бы очень хотел превратить некоторые из этих идей в JSR.

Доступ к полям объекта через прозрачный метод доступа — определенно та функция, которую мне не хватает в Java.

Что это такое?

В Java мы используем геттеры и сеттеры, которые позволяют получить доступ к свойству объекта. Я не буду говорить о преимуществах наличия методов получения и установки вместо открытых полей. Я предполагаю, что вы знаете об этом … В других языках (C #, AS3, …) вы можете явно объявить методы получения и установки свойства и используйте их так, как если бы вы использовали публичную собственность. Мой любимый синтаксис — это ActionScript3:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
//Object Declaration
public class MyObject {
       private var _myProperty:String;
 
       public function get myProperty():String {
                return _myProperty;
       }
 
       public function set myProperty(value:String):void {
              _myProperty = value;
       }
 
       public function get firstLetter():String {
               return _myProperty.substr(0,1);
       }
}
 
//Usage
var o:MyObject = new MyObject();
o.myProperty = 'A value'; //Set the property using the setter
trace(o.myProperty); //Print the value return by the getter
trace(o.firstLetter); //Print 'A'

Предложение синтаксиса Java

Поскольку я считаю синтаксис ActionScript 3 очень удобным, я считаю, что синтаксис Java должен быть очень похожим. Для этого потребуется добавить новые модификаторы : get и set .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
public class MyObject
{
 
    private String _name;
 
    public get String name() {
        return name;
    }
 
    public set void name(String name) {
        this.name = name;
    }
}
 
//Usage
MyObject o = new MyObject();
o.name = 'My name';
System.out.println('print entity : ' + o.name);

Выгоды

  • Использование аксессора прозрачно. Инкапсуляция сделана неявной. Вызывающая сторона не знает, вызывает ли она открытую переменную или метод доступа.
  • Лучшее программирование в стиле OO: с точки зрения внешнего класса vue объект теперь действительно имеет открытые методы и свойства, тогда как раньше он был только открытым методом.
  • Рефакторинг кода для изменения всех прямых обращений к полям объекта — это просто, просто нужно изменить соответствующий класс, а не все вызовы чтения / записи.
  • Больше не нужно иметь соглашения JavaBean для получения и установки. Некоторые библиотеки полагались на тот факт, что средства доступа myProperty называются [get|is|set]MyProperty . Теперь аксессоры определяются не соглашением, а договором. У нас может быть метод класса Class который извлекает метод доступа (getGetters (), getSetters ()). Еще раз большое улучшение ООП.

Недостатки

  • Потребуется изменить соглашение об именах полей объекта, поскольку метод и свойство могут иметь одно и то же имя. Нет сомнений в том, что JVM может позволить, чтобы свойство и метод имели одно и то же имя, это скорее проблема читабельности.

Реализация и проблемы

Реализация этой функции потребует добавления двух новых ключевых слов ( get и set ) к языку Java. Это плохо для ретро-совместимости, но это не большая проблема. Необходимо будет использовать параметр командной строки «-source», как это было сделано ранее, когда ключевое слово assert было добавлено в Java 1.4.

Это изменение также потребует изменения спецификации JVM и компилятора java для добавления двух новых модификаторов. Эти два новых модификатора необходимы в файле класса, чтобы идентифицировать, используя отражение, методы получения и установки класса.

Я считаю, что эта функция будет отличным улучшением языка Java. Как и все основные улучшения, он требует много работы. Если однажды я почувствую себя достаточно готовым представить JSR, то это точно будет именно этот!

Потокобезопасная проверка компиляции

В этой серии статей рассказывается, как, на мой взгляд, язык Java должен развиваться, чтобы оставаться основным языком выбора. В нем также представлены некоторые функции, иногда уже существующие на другом языке, которые я люблю, но которые не могут (или не должны быть) частью Java, по некоторым причинам, которые я объясню. Я бы очень хотел превратить некоторые из этих идей в JSR.

Проверка компиляции Thread Safe: что это?

Это возможность проверить, что ваша программа не будет иметь проблем из-за многопоточности. Насколько я знаю, ни один язык программирования не обеспечивает такую ​​функциональность (если вы знаете один, пожалуйста, дайте мне знать!).

В чем проблема?

Разработать программу, которая работает в нескольких потоках, легко, разработать что-то, что не будет иметь каких-либо странных ошибок из-за того, что механизм потока намного сложнее.

Почему параллельное программирование сложно?

Потому что, чтобы создать хорошее многопоточное приложение, вы должны быть очень осторожны и прекрасно знать язык Java и API: избегать тупиков, знать, когда использовать ключевое слово volatile , знать, что (или нет) поточно-ориентировано.

Другая трудность заключается в том, что тестирование / отладка многопоточных приложений очень сложны. Вы можете потратить несколько дней на размышления о том, почему в вашей огромной базе данных есть эта строка со странным значением даты… Чтобы окончательно осознать, что ваш со-разработчик (конечно, не вы, так как вы — гава-гуру) ;) ) использовал объект SimpleDateFormat, совместно используемый несколькими потоками… (Кстати, если вы не знали: да, SimpleDateFormat не является потокобезопасным)

Каково решение?

Потокобезопасная проверка компиляции! Это сделало бы разработку намного проще, если бы у вас было предупреждение: «В строке 36: не потокобезопасный код. Использование не потокобезопасного метода SimpleDateFormat.format ».

Почему это невозможно

Использование не поточно-безопасных API

На данный момент единственный способ узнать, являются ли используемые вами библиотеки / API-интерфейсы безопасными для потоков, — это прочитать Javadoc или исходный код. Таким образом, компилятор не может знать, является ли то, что вы называете, потокобезопасным или нет. Благодаря транзитивности, если вы не используете какой-либо механизм синхронизации, он не может узнать, является ли ваш код поточно-ориентированным или нет, поскольку вы используете эти библиотеки.

Одним из решений этой проблемы может быть создание аннотации @ThreadSafe для аннотирования классов и методов. Таким образом, любой элемент, аннотированный @ThreadSafe, будет рассматриваться компилятором как поточно-ориентированный. Конечно, все API, которые вы используете, должны быть правильно аннотированы … Помимо проверки компиляции, я думаю, что такая аннотация была бы хороша, чтобы сделать API более понятными.

Reflection API

Reflection API — другая проблема. Поскольку поток выполнения определяется во время выполнения, компилятор не может знать, какие методы будут вызваны, и поэтому не может определить, является ли то, что будет выполняться, потокобезопасным.

Компилятор должен знать контекст

Компилятор не может знать, будет ли то, что вы разрабатываете, выполняться в поточно-безопасной среде или нет. Например, если вы разрабатываете bean-компонент, который будет внедрен везде вашей любимой платформой CDI, компилятор не может этого знать.

Другими словами, компилятор знает меньше, чем вы, и поэтому не может определить, должно ли то, что вы программируете, быть поточно-ориентированным или нет. Допустим, вы программируете контроллер для своего приложения J2EE; Если вы не аннотируете свой контроллер гипотетической аннотацией @ThreadSafe, компилятор никогда не будет жаловаться. Проблема в том, что ваш контроллер должен быть поточно-ориентированным! Если вы не правильно аннотируете с помощью @ThreadSafe то, что должно быть поточно-ориентированным, у вас будут проблемы …

Механизм разных замков

Если бы единственным способом синхронизации ваших потоков было ключевое слово synchronized, компилятору было бы легче определить, может ли фрагмент кода выполняться одновременно или нет. К сожалению, это не так! У вас есть несколько способов убедиться, что ваш код будет выполняться только в правильном контексте ( ReentrantLock , ReadWriteLock , ручные блокировки с использованием файла, сокета, объекта, счетчика и т. Д.). Для меня эта единственная причина делает невозможной реализацию «проверки компиляции потока». Если компилятор не может определить механизм синхронизации, он ничего не может знать о безопасности потоков!

Вывод

Потокобезопасная проверка компиляции определенно была бы убийственной функцией Но для меня это невозможно реализовать, даже частично, и, вероятно, поэтому я никогда не видел эту функцию ни на каких языках.

Если у вас есть идеи по поводу решения или если вы знаете какой-либо язык, который делает это, даже частично, дайте мне знать!

Справка: Java SE 11: продвижение Java Forward — часть 1: введение , Java SE 11: продвижение Java Forward — часть 2: средство доступа к свойствам , Java SE 11: продвижение Java Forward — часть 3: проверка компиляции потокобезопасности от нашего партнера по JCG Тибо Делора в блоге InvalidCodeException .