Дельфин, монета и бриллиантовый оператор.


Релиз Java 7 должен выйти 28 Июля.
В связи с этой знаменательно датой, я наконец-то решил посмотреть, что нас всех ждет. Поскольку в последнее время в основном занимаюсь Scala, то на новые языковые фичи в Java не обращал серьезного внимания (только на тусовках java-программистов, плюс поглядывал что пишут в разных блогах жависты).

Итак Java 7.
Продолжая традиции именования (Java 5 – тигр, Java 6 – мустанг), у нового релиза кодовое имя “Дельфин”.
Список фич можно посмотреть здесь: http://www.oracle.com/technetwork/java/7-138633.html.

Технических новшеств очень много. Среди них самое интересное место занимает так называемый “Проект Монета (Project Coin)“.

Он содержит в себе небольшие (конечно с их точки зрения) изменения в языке:

– Strings in switch
– Binary integral literals and underscores in numeric literals
– Multi-catch and more precise rethrow
– Improved type inference for generic instance creation (diamond)
– try-with-resources statement
– Simplified varargs method invocation

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

Improved type inference for generic instance creation (diamond)

Это так называемый оператор diamond (бриллиант, алмаз). Думаю называется так, потому что чем-то похож на камень: <>.

В качестве примера часто приводят такой код:

// Java 7
        List a = new ArrayList<>();
// до Java 7
        List b= new ArrayList();

Это конечно очень красиво, т.к. мы смогли уменьшить размер кода. Но возникает вопрос, чем это лучше, если раньше можно сделать еще проще? Вот так:

// в  Java 7
        List a  = new ArrayList<>();
// до Java 7
        List b = new ArrayList();

Понятно, что мы здесь используем сырой тип (raw types) и поэтому некоторым программистам по “морально-этическим” соображениям такой код не нравится.
Хотя один java-программист даже не поленился и сравнил полученный байт-код: jdk-7-diamond-operator.
Он показал на примере, что никакой разницы от использования бриллианта в компилируемом байт-коде нет, т.к. весь этот сахар при компиляции пропадает.

Мне кажется, что более реальная польза, может быть показана в следующем примере:

        List a = new ArrayList<>();
       
        // Такой прокатит, хотя и ошибочный, что плохо.
        List b = new ArrayList(a);
        //  Такой уже отрубится компилятором, что хорошо.
        List c = new ArrayList<>(a);

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

try-with-resource

Появился новый интерфейс AutoCloseable. Причем не где-то там в io (как Closeable), а в самом java.lang!

Этот интерфейс был подсунут в иерархию над Closeable (Closeable extends AutoCloseable).
Таким образом, автоматически все потоки (_Stream) и читатели/писатели(Reader/Writer) становятся также AutoCloseable.
В AutoCloseable есть один метод void close() throws Exception.

Идея заключается в том, что если указать AutoCloseable переменные (в терминах Java 7 они называются ресурсы) в скобочках после try, то они всегда автоматически закроются при выходе из try блока.

В качестве примера как правило приводят обычно что-то вроде:

// До Java 7
static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
  BufferedReader br = new BufferedReader(new FileReader(path));
  try {
    return br.readLine();
  } finally {
    if (br != null) br.close();
  }
}

// в Java 7
static String readFirstLineFromFile(String path) throws IOException {
  try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
  }
}

Можно поэкспериментировать самому:

    static class A implements AutoCloseable {
        public void close() {
            System.out.println("A.close()");
        }
    }

    static class B implements AutoCloseable {
        public void close() {
            System.out.println("B.close()");
        }
    }

    private static void autoCLoseableCheck() {
        try (A a = new A(); B b = new B()) {
            System.out.println("1");
            throw new RuntimeException();
        } catch (RuntimeException e) {
            System.out.println("exc");
        } finally {
            System.out.println("finally");
        }
    }

Выведет на консоль:

1
B.close()
A.close()
exc
finally

Из всего этого можно сделать несколько интересных выводов:
1. try теперь может быть без catch и finally. Раньше были бы ошибки компиляции.
2. Ресурсов может быть несколько, перечисляются они через ;.
3. Закрываются ресурсы до вызова кода в catch и до finnaly
4. Вызов close() происходит в ОБРАТНОМ порядке (как в стеке). То есть, если мы указали сначала A a, затем B b, то вначале вызовется b.close(), а затем a.close().

Продолжение следует…

Любое использование либо копирование материалов или подборки материалов сайта, элементов дизайна и оформления допускается лишь с разрешения правообладателя и только со ссылкой на источник: programador.ru

Телеграм канал: @prgrmdr
Почта для связи: vit [at] programmisty.com