Андрей Дмитриев andrei-dmitriev@yandex.ru (с)2009 Java SE: языковые возможности.

Презентация:



Advertisements
Похожие презентации
Новые возможности Java 5 Java Advanced. 2Georgiy KorneevJava Advanced / Новые возможности Java 5 Содержание Перечисления Метаданные Другие возможности.
Advertisements

1 © Luxoft Training 2013 Модуль 8 Введение Задачи аннотаций Стандартные аннотации Создание собственных аннотаций 8-1 Аннотации.
1 © Luxoft Training 2012 Java: расширенные вопросы Модуль #8.
Обобщения ( generics) Обобщения – это классы, структуры, интерфейсы и методы, в которых некоторые типы сами являются параметрами. Эти типы перечисляются.
Программная инженерия Андрей Дмитриев ©2009.
Новые возможности Java 5 Java Advanced. 2Georgiy KorneevJava Advanced / Новые возможности Java 5 Краткое содержание 1.Что такое generic 2.Реализация Generic.
Software engineering Дмитриев Андрей Владиславович ©
Полиморфизм Полиморфизм (polymorphism) - последний из трех "китов", на которых держится объектно-ориентированное программирование Слово это можно перевести.
Test 6 Вопрос 1. Как можно уничтожить объект в Java? a)присвоить null всем ссылкам на объект b)вызвать Runtime.getRuntime().gc() c)вызвать метод finalize()
Коллекции: алгоритмы, генерики. Приведение типов Предположения о типах объектов: void innerMethod( Object o ){ //Ошибка времени выполнения int val = (Integer)o;
Изучение динамического определения типов. Класс Class. Динамическая загрузка и инстанцирование классов. В Java вся информация о классе хранится в специальном.
1 Классы в Java Ключевое слово class означает: Я говорю тебе, как выглядит новый тип объекта. Класс является базовым элементом объектно-ориентированного.
Синтаксис языка Java. Символы и синтаксис Перевод строчки эквивалентен пробелу Регистр в именах различается.
Встроенная документация Java Андрей Дмитриев Инженер-программист Sun Microsystems Февраль 2008.
Типы данных Инна Исаева. Переменные Переменная - это как ящик, в котором можно хранить данные. Каждая переменная имеет своё имя, она служит для хранения.
Лекция 4. Введение в С++ Наследование, множественное наследование. Конструкторы, деструкторы. Виртуальные функции.
Исключения в Java. Исключения – это механизм взаимодействия между кодом, приведшим к ошибке, и кодом, обрабатывающим ошибку Исключение выбрасывается (throw),
Практическое программирование на Java к.ф.-м.н. Козлов Дмитрий Дмитриевич Кафедра АСВК, Лаборатория Вычислительных комплексов.
Кафедра ОСУ, Java 2007 Слайд 1 Определение классов и методов Java- программа состоит из объектов различных классов, взаимодействующих друг.
Java, каф.ОСУ, АВТФ1 Определение классов и методов Java- программа состоит из объектов различных классов, взаимодействующих друг с другом. Каждое.
Транксрипт:

Андрей Дмитриев (с)2009 Java SE: языковые возможности

Java SE: Упор на качестве, стабильности, совместимости Большой вклад в масштабируемость Поддержка широкого ряда приложений от небольших до крупных промышленных приложений Постоянная разработка новой функциональности языка Сделать разработку ПО еще проще

7 самых главных нововведений в языке Java Generics Autoboxing/unboxing ForEach Enums Varargs Static import Metadata (annotations)

Generics Autoboxing/unboxing ForEach Enums Varargs Static import Metadata (annotations)

Пример типичной проблемы Vector v = new Vector(); v.add(new Integer(4)); OtherClass.test(v);... static void test(Collection c) { for (Iterator it = c.iterator(); it.hasNext();) /* ClassCastException */ if (((String)it.next()).length() == 4) it.remove(); }

Generics Проблема: элементы в коллекции Компилятору недоступна информация о типе хранимых элементов Необходимо приведение типов (casting) Возможны ошибки во время выполнения программ (ClassCastException) Решение: Cообщать компилятору тип хранимого элемента Приведение типов автоматически производится компилятором Гарантия успеха – информация об ошибках доступна на этапе компиляции

Что такое Generics? Generics обеспечивают абстракцию на уровне типов Классы, интерфейсы, методы могут быть параметризованный Generics предоставляют возможность создавать безопасный код (type safe code) Если приложение компилируется без ошибок и предупреждений, тогда при выполнении оно не выбросит никаких незапланированных ClassCastException Generics повышают удобочитаемость исходного кода

Используем Generics Определение: LinkedList использует параметр типа (type parameter) T, который представляет тип элементов Использование: Заменяем конкретным типом. Например, или > LinkedList может хранить только элементы типа или подтипа Integer LinkedList li = new LinkedList (); li.add(new Integer(0)); Integer i = li.iterator().next();

Используем Generics: пример // Определяем параметризованный класс LinkedList class LinkedList { void add(T element) {...}... } // Использование объявленного класса // с конкретным типом String LinkedList ls = new LinkedList (10); ls.add(new Integer(5)); // Compiler error! ls.add(TEST); // OK!

Используем Generics: extends extends позволяет вводить ограничения // объявление class MyClass { void method(T t) {...} } // Некорректное использование, ошибка компиляции! MyClass myClass = new MyClass (); // Правильное использование MyClass myClass = new MyClass ();

Generics: некоторые факты Можно использовать несколько аргументов параметризации class MyClass {...} Generics – возможно, неудачное название, по сути parameterised types Generics – это не templates в С++ Начиная с J2SE 5.0, все коллекции переписаны с использованием generics

Традиционное заблуждение 1 Универсальный метод для вывода всех элементов для любой коллекции void printCollection(Collection c) { for (Object o : c) System.out.println(o); }

Традиционное заблуждение 1 Универсальный метод для вывода всех элементов для любой коллекции void printCollection(Collection c) { for (Object o : c) System.out.println(o); } Неправильно!!! > вызов с параметром типа Collection выдаст compile-time error > Коллекция с параметром типа Object НЕ супертип для всех других коллекций.

Наследование Generic-классы не имеют отношения наследования по характеристике типа ArrayList ao = new ArrayList (); // Error Но у классов как таковых наследование присутствует ArrayList ai = new ArrayList (); List li = new ArrayList (); Collection ci = new ArrayList (); Collection cs = new Vector (4);

Наследование: продолжение У элементов также сохраняются отношения наследования Пример с коллекцией: ArrayList an = new ArrayList (); an.add(new Integer(5)); an.add(new Long(1000L)); an.add(new String(hello)); //compile error

Как быть? Помогут Wildcards ? - это wildcard type Collection - обозначает коллекцию неизвестного типа Static void printCollection(Collection c) { for (Object o : c) System.out.println(o); } public static void main(String[] args) { List li = new ArrayList (10); printCollection(li); // No Compile error Collection cs = new Vector (); printCollection(cs); // No Compile error }

Bounded Wildcards wildcard может использоваться с extends public void drawAll(List s) {... } List o = getObjects(); drawAll(o);// compile-time error List c = getCircles(); drawAll(c);// ok! List t = getTriangles(); drawAll(t);// ok!

Bounded Wildcards wildcard может использоваться с super public void drawAll(List s) {... } List o = getObjects(); drawAll(o);// ok! List c = getShapes(); drawAll(c);// ok! List t = getTriangles(); drawAll(t);// compile-time error

Традиционное заблуждение 2 ? - это не любой тип, а неизвестный тип Пример ошибочного использования: static void aToC(Object[] a, Collection c) { for (Object o : a) c.add(o); /* COMPILER ERROR */ }

Правильное решение Объявить параметризацию метода заранее Компилятор осуществит необходимую проверку static void aToC(T[] a, Collection c) { for (T o : a) c.add(o); /* No compiler error */ } String[] sa = new String[100]; String[] ia = new Integer[100]; Collection ci = new ArrayList (); Collection cs = new ArrayList (); aToC(sa, cs); /* здесь T - String */ aToC(ia, ci); /* здесь T - Integer */

Коллекции неизвестного типа Добавление и получение элемента неизвестного типа - компилятор не имеет информации о типе, поэтому запрещает все, кроме null ArrayList a1 = new ArrayList (10); a1.add(new Integer(3)); // Compile error a1.add(new Long(100L)); // Compile error a1.add(new Object()); // Compile error a1.add(null);// ОК! Object o = a1.get(0); // ОК! Number n = a1.get(0); // Compile error Integer i = a1.get(0); // Compile error

Raw Type Можно создать объект генерефицированного класса без указания типов аргументов Классы Pre-J2SE 5.0 продолжают функционировать под J2SE 5.0 JVM как raw тип // обычно List ls = new LinkedList (); // Raw type List lraw = new LinkedList();

Type Erasure Вся информация о generic исчезает во время компиляции, во время выполнения она уже отсутствует Все параметризованные классы используют один класс > Классы представляющие ArrayList, ArrayList те же самые, что и ArrayList

Что делать нельзя? Пример недопустимого кода: public class MyList { public E[ ] toArray() { return new E[5]; // compile error } public boolean canAdd(Object o) { return (o instanceof E); // compile error } public E convertToE(Object o) { return (E) o; // compile warning, unchecked cast } }

Чего стоит избегать? Пример 1 class D { void foo(T t) {} void foo(Number n) {} } class C extends D {} // compile error Пример 2 class D { void foo(Number n, T t) {} void foo(S s, Object o) {} } class C extends D {} // compile error Пример 3 class D { void foo(Object o, T t) {} void foo(S s, Object o) {} } class C extends D {} // compile error

Type-safe Code Компилятор гарантирует, что: > Генерируемый код будет корректен с точки зрения типов, либо он сгенерирует предупреждение (warning), например, при использовании Raw типа > Если код компилируется без предупреждений и не использует приведений, тогда во время выполнения не будет брошен ClassCastException > Type safe code

Используя Generics Простая миграция. Благодаря бинарной совместимости, использовать gererics можно прямо сейчас, не ожидая других Необходимо избегать raw-типов, они приводят к небезопасному коду. Если все же используются raw-типы или старые библиотеки классов, необходимо удостовериться, что небезопасные предупреждения (warnings) действительно лишь только предупреждения

Ограничения Нельзя создавать объекты, используя параметры типа T t = new T(); //ошибка Ограничения для статических членов класса static T t; //ошибка Массивы class Test { T values; //ok Test(T[] new) { values = new T[10]; //ошибка values = new; //ok } } Test iTest[] = new Test [10] //ошибка Test iTest[] = new Test [10] //ok

Ограничения Настраиваемый класс не может расширять класс Throwable class Test extends Throwable {} //ошибка class t { //ok void method() throws T { } }

Generics Autoboxing/unboxing ForEach Enums Varargs Static import Metadata (annotations)

Autoboxing примитивных типов Проблема: > Преобразование между примитивными типами (int, long, etc) и классами-оболочками (Integer, Long, etc) > Обратное преобразование > Необходимо, например, при добавлении в коллекции Решение: возложить весь труд на компилятор Byte byteObj = 22; // Boxing conversion int i = byteObj // Unboxing conversion ArrayList al = new ArrayList(); al.add(22); // Boxing conversion

Generics Autoboxing/unboxing ForEach Enums Varargs Static import Metadata (annotations)

Расширение цикла (foreach) Проблема: (pre-J2SE 5.0) > Итерация по коллекции не проста > Часто итератор используется лишь для доступа к элементу > Использование итератора может порождать ошибки Решение: компилятор сделает все сам > Новый синтаксис цикла for (variable : collection) > Работает с коллекциями, массивами и пользовательскими классами, которые реализуют интерфейс Iterable

Расширение цикла, пример Старый код void cancelAll(Collection c) { for (Iterator i = c.iterator(); i.hasNext(); ){ TimerTask task = (TimerTask)i.next(); task.cancel(); } Новый код void cancelAll(Collection c) { for (TimerTask task : c) task.cancel(); }

Generics Autoboxing/unboxing ForEach Enums Varargs Static import Metadata (annotations)

Type-safe Enumerations Проблема: > Часто требуется переменные с ограниченным количеством значений > Например, цвет светофора: зеленый, красный, желтый > Прежнее решение – обходные пути Решение: новый тип объявления класса > Тип enum содержит public поля для каждой константы > Новое ключевое слово enum > Работает с конструкцией switch

Новый класс enum Новое ключевое слово enum добавлено в язык Java Enum – это специальный тип класса Enum может быть определен везде, где может быть определен интерфейс > Внутри пакета > Внутри класса > Не может находиться внутри метода Enum классы не могут иметь подклассов

Enumeration пример: 1 public enum Suit { spade, diamond, club, heart }; public enum Value { ace, two, three, four, five, six, seven, eight, nine, ten, jack, queen, king }; List deck = new ArrayList (); for (Suit suit : Suit.values()) for (Value value : Value.values()) deck.add(new Card(suit, value)); Collections.shuffle(deck);

Enumeration пример: 2 public enum TrafficLight { RED(30) { public TrafficLight next() { return GREEN; }}, AMBER(10) { public TrafficLight next() { return RED; }}, GREEN(40) { public TrafficLight next() { return AMBER; }}; private final int duration; TrafficLight(int duration) { this.duration = duration; } public int getDuration() { return duration; } } TrafficLight light = TrafficLight.RED; String lightName = light.name(); // RED int lightDuration = light.getDuration(); //30 TrafficLight nextLight = light.next(); // GREEN

Новые классы для enum Все enum классы наследуются от java.lang.Enum > value() – возвращает массив кконстант > valueOf(String str) – возвращает перечисляемую константу по имени Существуют общие методы для всех констант, например: > name(): имя константы, заданой в enum > ordinal(): позиция константы в enum (начиная с 0)используется редко.

Generics Autoboxing/unboxing ForEach Enums Varargs Static import Metadata (annotations)

Varargs Проблема: > Хочется иметь методы с непостоянным числом параметров > Можно использовать массив, но пользователю придется его создать > java.text.MessageFormat Решение: возложить весь труд на компилятор > public static String format (String fmt, Object... args); > В Java теперь тоже есть printf(...)

Создание varargs-метода Последний параметр – это массив Заменяем [ ] на... Раньше: public static int sum(int[ ] a) { int t = 0; for (int i = 0; i < a.length; i++) t += a[i]; return t; } x = sum(new int[]{2, 3, 4}); Теперь: public static int sum(int... a) { int t = 0; for (int i = 0; i < a.length; i++) t += a[i]; return t; } x = sum(2, 3, 4);

Varargs API было модифицировано, чтобы методы могли принимать переменное число аргументов > Class.getMethod > Method.invoke > Constructor.newInstance > Proxy.getProxyClass > MessageFormat.format printf > System.out.printf(%d + %d = %d\n, a, b, a+b); Могут быть пролемы при перегрузке

Generics Autoboxing/unboxing ForEach Enums Varargs Static import Metadata (annotations)

Static Imports Проблема: > Полностью конкретизировать внешний класс, члены которого используются в текущем коде Решение: новый синтаксис import'а > import static TypeName.Identifier; > import static Typename.*; > Может быть использован для статических методов, enums и констант например, Math.sin(x) станет sin(x)

Static Imports, примеры import static java.lang.System.out;... out.println(hello, world); // == System.out.println import static java.lang.System.*;... out.println(hello, world); gc(); // == System.gc(); exit(1); // == System.exit(1);

Generics Autoboxing/unboxing ForEach Enums Varargs Static import Metadata (annotations)

Как используются аннотации? Внедрение дополнительной информации в исходный код Аннотации используются для того, чтобы влиять на то, как программы обрабатываются утилитами и библиотеками Компилятор, IDE, Runtime tools

Ad-hoc аннотации до Java 5.0 Примеры смысловых почти аннотаций до J2SE 5.0 Transient Serializable javadoc комментарии Xdoclet Аннотации c J2SE 5.0 предоставляют стандартизованный, мощный механизм

Почему аннотации? Предоставляют декларативный стиль программирования Меньше программирования, так как специализированные утилиты сгенерируют все необходимое окружение Легче поддается изменению Теперь нет необходимости сопровождать дополнительные файлы с информацией Вся информация хранится в файле с исходным кодом

Определяем аннотацию? Определение аннотаций схоже с определением интерфейсов Ключевая Каждый метод определяет элемент аннотации Методы не должны иметь параметров или объявлять бросаемые исключения (throws) Возвращаемые типы ограничены примитивами, классом String, классом Class, enums, аннотациями, а также массивами перечисленных типов Методы могут иметь значения по умолчанию

Пример: определение аннотации /** * Описывает Request-For-Enhancement(RFE) */ RequestForEnhancement { int id(); String synopsis(); String engineer() default "[unassigned]"; String date(); default "[unimplemented]"; }

Использование аннотаций Как только аннотация определена, она может быть использованя для аннотирования других определений Класс, метод, поле Аннотации – это специальтный модификатор, который может использоваться аналогично public, static, final и.т.п По соглашению аннотации предшествуют другим модификаторам Аннотации состоят имени аннотации и пар элемент-значение

Пример: использование id = , synopsis = "Enable time-travel", engineer = "Mr. Peabody", date = "4/1/3007" ) public static void travelThroughTime(Date destination) {... } Аннотируется метод travelThroughTime

3 различных вида аннотаций Marker Single value Обычные

Marker аннотации Аннотации без элементов Пример Preliminary { } Использование – не обязательно использовать скобки public class TimeTravel {... }

Single Value аннотации Аннотации с одним элементом Название элемента должно быть value Пример Copyright { String value(); } Использование – не обязательно указывать имя элемента и знак равно Yoyodyne Propulsion Systems") public class OscillationOverthruster {... }

Обычные аннотации Пример уже был представлен Пример RequestForEnhancement { int id(); String synopsis(); String engineer() default "[unassigned]"; String date(); default "[unimplemented]"; } id = , synopsis = "Enable time-travel", engineer = "Mr. Peabody", date = "4/1/3007" ) public static void travelThroughTime(Date destination) {... }

Meta-аннотации Используются для аннотирования Определяет как долго будет хранится информация аннотации Enum RetentionPolicy SOURCE, CLASS (Default), Ограничение использования аннотации Enum ElementType TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE

Пример: аннотация и мета-аннотация Accessor { String variableName(); String variableType() default "String"; } // = "name") public String myVariable;

Reflection и метаданные Marker аннотации boolean isBeta = MyClass.class.isAnnotationPresent(BetaVe rsion.class); Single value аннотации String copyright = MyClass.class.getAnnotation (Copyright.class).value(); Обычные аннотации Author author = MyClass.class.getAnnotation(Author.class ); String first = author.getFirst(); String last = author.getLast();

Пример программы Необходимо создать простую программу на базе аннотаций для автоматического тестирования 1. Необходима marker-аннотация для определения методов, которые будут тестироваться 2. Написать программу, часть методов которой будут аннотированы анотацией из п.1 3. Запустить утилиту тестирования, которая будет итерировать по всем методам определенного класса и запускать те, которые помечены условленной аннотацией

Шаг 1 Определение marker-аннотации import java.lang.annotation.*; /** * Указывает, на то, что метод тестируемый * Данная аннотаия должна использоваться только * для методов и доступна в режиме Test { }

Шаг 2 Пишется программа, некоторые методы аннотированы public class Foo public static void m1() { } public static void m2() { public static void m3() { throw new RuntimeException("Boom"); } public static void m4() { public static void m5() { } public static void m6() { public static void m7() { throw new RuntimeException("Crash"); } public static void m8() { } }

Шаг 3 Утилита тестирования, запускающая необходимые методы public class RunTests { public static void main(String[] args) throws Exception { int passed = 0, failed = 0; for (Method m : Class.forName(args[0]).getMethods()) { if (m.isAnnotationPresent(Test.class)) { try { m.invoke(null); passed++; } catch (Throwable ex) { System.out.printf( "Test %s failed: %s %n", m, ex.getCause()); failed++; } System.out.printf("Passed: %d, Failed %d%n", passed, failed); }

Запуск программы Результат: $ java RunTests Foo Test public static void Foo.m3() failed: java.lang.RuntimeException: Boom Test public static void Foo.m7() failed: java.lang.RuntimeException: Crash Passed: 2, Failed 2

Пример Раньше – много дополнительного кода public interface PingIF implements java.rmi.Remote { public void foo() throws java.rmi.RemoteException; } public class Ping implements PingIF { public void foo() {} } Теперь – все генерируется автоматически public class Ping { void foo() {} }

Q&A