[ главная ]   [ рейтинг статей ]   [ справочник радиолюбителя ]   [ новости мира ИТ ]



Ответов: 0
25-02-12 07:01







   Web - программирование
PHP


ASP






XML



CSS

SSI





   Программирование под ОС











   Web - технологии








   Базы Данных









   Графика






Данные




Программирование под ОС / Java /

Особенности Java 5

Java 5 обладает некоторыми полезными возможностями. В данной статье мы рассмотрим их и узнаем, как можно извлечь из них выгоду. В этой части мы рассмотрим auto-boxing foreach.

Возможности Java 5

Несколько интересных возможностей были добавлены к языку программирования Java в версии 1.5, также называемой Java 5. Этими возможностями являются auto-boxing, foreach, enums, varargs, annotation, static imports, и generics. Большинство из данных возможностей может считаться прогрессом. Они улучшают производительность разработчиков путем сокращения многословного синтаксиса и делая код более интуитивным. Следующий рисунок демонстрирует наше мнение о пригодности данных функций:
Особенности Java 5 - Java - Программирование - Программирование, исходники, операционные системы

Свойства в левой части (foreach, varargs, auto-boxing, enum) хороши. Annotation очень полезно, но мы также должны понять где и когда его использовать. Static import предоставляет только несущественную выгоду (и может привести к плохому коду).

Auto-boxing для объектных оболочек

Java обладает двумя классами: objects и primitives. Вы не можете смешивать их в вашем коде. Но что, если вы хотите написать обобщенный программный интерфейс программирования, который сможет принять параметры любого типа. Это выполняется в Reflection API. Давайте напишем простую имитацию метода invoke(), принадлежащего Reflection:
package com.agiledeveloper;

class A {}
class B {}

public class Test
{
    public static void foo1(A obj)
    {
        System.out.println("foo вызван с" + obj);
    }

    public static void foo2(A obj1, B obj2)
    {
        System.out.println("foo2 вызван с  " + obj1 + " и " + obj2);
    }

    // слабая имитация программного интерфейса для демонстрации общей идеи
    public static void invoke(String method, Object[] args)
    {
        if (method.equals("foo1"))
        {
            foo1((A) args[0]);
        }
        if (method.equals("foo2"))
        {
            foo2((A) args[0], (B) args[1]);
        }
    }

    public static void main(String[] args)
    {
        invoke("foo1", new Object[]{new A()});
        invoke("foo2", new Object[]{new A(), new B()});
    }
}
В main() мы вызываем invoke() с foo1 , а затем с foo2. Для того, чтобы послать любое число параметров, invoke() принимает массив объектов. Не существует препятствий для отсылки объекта A или объекта B данному методу. Тем не менее, давайте добавим другой метод:
    public static void foo3(int value)
    {
        System.out.println("foo3 вызван с" + value);
    }
Как же вызвать данный метод используя метод invoke()? invoke() ожидает массив объектов в то время, как foo3() ожидает значение типа int. В предыдущих версиях Java вам пришлось бы обернуть int в объект и послать его методу invoke() . Стандартным объектом для упаковывания int является Integer. Аналогично, для Double есть double, Character для char, и так далее. В то время как Integer.class представляет собой класс Integer, Integer.TYPE представляет собой примитивный тип int , которому данный класс служит оболочкой.

Такой подход к ручной обертке и распаковке имеет несколько недостатков:
  • Он приводит к нагромождению кода
  • Он требует больше работы от разработчиков
  • Выглядит не натурально
  • Пугает новичков программистов
Давайте модернизируем метод invoke()и посмотрим на способ его вызова :
    public static void invoke(String method, Object[] args)
    {
        if (method.equals("foo1"))
        {
            foo1((A) args[0]);
        }
        if (method.equals("foo2"))
        {
            foo2((A) args[0], (B) args[1]);
        }
        if (method.equals("foo3"))
        {
            foo3(((Integer) (args[0])).intValue());
        }
    }
А вызов будет выглядеть следующим образом:
        invoke("foo3", new Object[]{new Integer(3)}); // до  Java 1.4

Заметьте, как вы помещаете (оборачиваете) значение 3 в объекте Integer . Аналогично, в вызове к foo3() в invoke(), вам необходимо распаковать данное значение.

В Java 5, функции auto-boxing и auto-unboxing назначены для разрешения данного излишкаi. Хотя все это проходит за занавесом, на уровне исходного кода, нам не нужно этого выполнять. Вот модифицированный код:

invoke("foo3", new Object[] {3});

Указанный выше код при компиляции переводится таким образом, что значение 3 автоматически упаковывается в объект Integer.

Давайте изучим другой пример – мы добавим метод foo4() как это показано ниже :

    public static Integer foo4(Integer v)
    {
        System.out.println("foo4 вызван с " + v.intValue());
        return new Integer(5);
    }
Теперь вот как его можно вызвать используя новую функцию Java 5 auto-boxing/unboxing:
        int someValue = foo4(4);
        System.out.println("Результат вызова foo4 " + someValue);
Как вы видите, данный код выглядит более натурально и занимает меньше места. Доводы за и против:
  • Поймите, что оборачивание и распаковка происходит за занавесом. Посмотрите на сгенерированный код:
             92:  iconst_4
             93:  invokestatic    #31;
          //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
             96:  invokestatic    #33;
          //Method foo4:(Ljava/lang/Integer;)Ljava/lang/Integer;
             99:  invokevirtual   #23;
          //Method java/lang/Integer.intValue:()I
             102: istore_1
    Этот код кажется обманывающим - у него есть проблемы с производительностью, особенно если вы вызываете методы со значительными вычислительными нуждами.
  • Если объект Integer равен null, его назначение int в результате вызовет выброс исключения – NullPointerException.
  • Поймите, что означает == . Для объектов вы сравниваете идентичность, а для примитивных типов вы сравниваете значение. В случае с auto-unboxing происходит сравнение, основанное на значениях.
  • Используйте его только когда производительность не важна.

foreach

Циклы - это структура управления, которая существовала со времен создания языков программирования. Старый добрый синтаксис циклов, который вы чаще всего используете:
for(int i = 0; i < arr.length; i++)
{
    ... = arr[i] ...
}
Хотя данная структура проста, нам приходится использовать индекс i даже если в нем нет необходимости.

Но что, если вы хотите пройтись по набору, как ArrayList? Вы сделаете что-то наподобие этого:
for(Iterator iter = lst.iterator(); iter.hasNext(); )
{
    System.out.println(iter.next());
}

Не настолько элегантно, не правда ли? В выражении for, у вас нет ничего после последней ;. Вам необходимо вызвать метод next() в пределах тела цикла для того, чтобы перейти к следующему элементу и в то же время получить элемент для обработки.

Введенный цикл foreach в Java 5 упрощает процесс циклов. Давайте рассмотрим пример того, как вы можете использовать новый и старый способы организации циклов:

package com.agiledeveloper;

import java.util.ArrayList;
import java.util.Iterator;

public class Test
{
    public static void main(String[] args)
    {
        String[] messages = {"Привет", "Здравствуйте", "Спасибо"};

        for (int i = 0; i < messages.length; i++)
        {
            System.out.println(messages[i]);
        }

        for (String msg : messages)
        {
            System.out.println(msg);
        }

        ArrayList lst = new ArrayList();
        lst.add(1);
        lst.add(4.1);
        lst.add("тест");

        for (Iterator iter = lst.iterator(); iter.hasNext();)
        {
            System.out.println(iter.next());
        }

        for (Object o : lst)
        {
            System.out.println(o);
        }

        ArrayList<Integer> values = new ArrayList<Integer>();
        values.add(1);
        values.add(2);

        int total = 0;

        for (int val : values)
        {
            total += val;
        }

        System.out.println("Всего : " + total);
    }
}
foreach был тактично создан для избежания введения других ключевых слов:
        for (String msg : messages)

Вместо придумывания нового ключевого слова “foreach” разработчики решили использовать старый добрый “for”. Также, “in” может быть использовано в существующем коде для полей, переменных или методов. Но было решено использовать : . В пределах цикла foreach, msg представляет собой элемент String в пределах массива String[].

Как вы могли бы заметить, организация циклов значительно упрощена, более элегантна (за исключением : ), и легка. Но что на самом деле происходит? Давайте опять изучим код.

        for (String msg : messages)
        {
            System.out.println(msg);
        }
порождает следующий код :
   51:  aload_1
   52:  astore_2
   53:  aload_2
   54:  arraylength
   55:  istore_3
   56:  iconst_0
   57:  istore  4
   59:  iload   4
   61:  iload_3
   62:  if_icmpge       85
   65:  aload_2
   66:  iload   4
   68:  aaload
   69:  astore  5
   71:  getstatic       #6;
//Field java/lang/System.out:Ljava/io/PrintStream;
   74:  aload   5
   76:  invokevirtual   #7;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
   79:  iinc    4, 1
   82:  goto    59
Для массива foreach просто преобразовывается в старый for. Давайте посмотрим что происходит с:
        for (Object o : lst)
        {
            System.out.println(o);
        }
где lst является ArrayList. Вот байтовый код :
   157: aload_2
   158: invokevirtual   #22;
//Method java/util/ArrayList.iterator:()Ljava/util/Iterator;
   161: astore_3
   162: aload_3
   163: invokeinterface #18,  1;
//InterfaceMethod java/util/Iterator.hasNext:()Z
   168: ifeq    190
   171: aload_3
   172: invokeinterface #19,  1;
//InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
   177: astore  4
   179: getstatic       #6;
//Field java/lang/System.out:Ljava/io/PrintStream;
   182: aload   4
   184: invokevirtual   #20;
//Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   187: goto    162

Как вы уже могли заметить, в данном случае foreach преобразуется в for , циклирующий через Iterator.

Итак, foreach просто является синтаксисом, который преобразуется в традиционный цикл во время компиляции.

В указанном выше примере мы использовали foreach к String[] и к ArrayList. А что, если вы хотите использовать foreach на вашем собственном классе? Вы можете так сделать, но ваш класс должен реализовывать интерфейс Iterable. Это все очень просто - для того, чтобы foreach работал, вы должны возвратить Iterator. Конечно, вы знаете что Collection предоставляет итератор. Тем не менее, для того, чтобы использовать foreach на вашем собственном классе не будет выгодно, если вам пришлось бы использовать громоздкий интерфейс Collection. Интерфейс Iterable имеет всего лишь один метод :

/** Реализация данного интерфейса позволяет объекту становиться  целью выражения "foreach".
 */
public interface Iterable<T> {

    /**
     * Возвращает итератор через набор элементов типа T.
     *
     * @return an Iterator.
     */
    Iterator<T> iterator();
}
Давайте попробуем следующее :
//Wheel.java
package com.agiledeveloper;

public class Wheel
{
}

//Car.java
package com.agiledeveloper;

import java.util.Iterator;
import java.util.ArrayList;

public class Car implements Iterable<Wheel>
{
    ArrayList<Wheel> wheels = new ArrayList<Wheel>();

    public Car()
    {
        for(int i = 0; i < 4; i++)
        {
            wheels.add(new Wheel());
        }
    }

    public Iterator<Wheel> iterator()
    {
        return wheels.iterator();
    }
}
Теперь вы можете использовать foreach для объекта Car, как это показано ниже :
        Car aCar = new Car();
        for(Wheel aWheel : aCar)
        {
            // aWheel ...
        }
Доводы за и против :
  • foreach выглядит проще, элегантнее и легче.
  • Но вы не можете его использовать в любое время. Если вам нужен доступ к индексу в наборе (для установки или изменения значений) или же вам необходим доступ к итератору (к примеру, для удаления элемента), то в этом случае вы не можете использовать foreach.
  • Пользователи вашего класса не смогут использовать foreach с вашим объектом если вы не реализуете интерфес Iterable.

Вывод

Java 5 обладает некоторыми интересными возможностями. В первой части мы обсудили две вещи: auto-boxing и foreach. Эти функции избавляют вас от громоздкости кода и делают его более понятным. Тем не менее, они всего лишь усовершенствованный синтаксис и они не улучшают производительность вашего кода. Оставшиеся возможности мы обсудим в следующей части данной статьи.


Комментарии

 Ваш комментарий к данному материалу будет интересен нам и нашим читателям!



Последние статьи: Программирование под ОС / Java /

Особенности Java 5
23-02-2010   

Java 5 обладает некоторыми полезными возможностями. В данной статье мы рассмотрим их и узнаем, как можно извлечь из них выгоду. В этой части мы рассмотрим auto-boxing foreach... подробнее

Кол. просмотров: общее - 3240 сегодня - 0

Особенности Java 5. Часть 2
23-02-2010   

В первой части мы обсудили новые возможности Java 5 относительно функции auto-boxing и цикла foreach. В данной части мы обсудим поддержку функций с переменным числом аргументов и статическое импортирование (static import). Поскольку другие функции, такие как enum, annotation, и generics, заслуживают отдельной статьи, мы их не будет демонстрировать в данной... подробнее

Кол. просмотров: общее - 3147 сегодня - 1

Расширение функциональности элементов пользовательского интерфейса в Java
05-05-2009   

Довольно часто при создании приложений с GUI (stand alone приложений или апплетов) приходится сталкиваться с необходимостью несколько изменить внешний вид и поведение стандартных компонентов пользовательского интерфейса... подробнее

Кол. просмотров: общее - 3417 сегодня - 2

Введение в сервлеты
05-05-2009   

Что такое сервлет ? Это класс порожденный от класса HttpServlet с переопреденными методами doGet и doPost (управление приходит в один из этих методов в зависимости от того какого типа был запрос. Надеюсь у Вас есть некоторый опыт в cgi-программировании... подробнее

Кол. просмотров: общее - 3107 сегодня - 1

Java Server Pages
05-05-2009   

Технология Java Server Pages (JSP) является составной частью единой технологии создания бизнес-приложений J2EE. JSP - это альтернативная методика разработки приложений... подробнее

Кол. просмотров: общее - 3210 сегодня - 1



  WWW.COMPROG.RU - 2009-2012 | Designed and Powered by Zaipov Renat | Projects