Скрытые возможности Java

Прочитав « Скрытые возможности C#», я задался вопросом: «Какие скрытые возможности Java»?

Ответов (25)

Передача управления в блоке finally отбрасывает любые исключения. Следующий код не генерирует исключение RuntimeException - он теряется.

public static void doSomething() {
    try {
      //Normally you would have code that doesn't explicitly appear 
      //to throw exceptions so it would be harder to see the problem.
      throw new RuntimeException();
    } finally {
      return;
    }
  }

С http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html

JDK 1.6_07 + содержит приложение под названием VisualVM (bin / jvisualvm.exe), которое представляет собой красивый графический интерфейс поверх многих инструментов. Это кажется более всеобъемлющим, чем JConsole.

Я думаю, что еще одна «недооцененная» особенность java - это сама JVM. Вероятно, это лучшая доступная виртуальная машина. И он поддерживает множество интересных и полезных языков (Jython, JRuby, Scala, Groovy). Все эти языки могут легко и беспрепятственно взаимодействовать друг с другом.

Если вы разрабатываете новый язык (как в случае со scala), у вас сразу становятся доступными все существующие библиотеки, и поэтому ваш язык «полезен» с самого начала.

Все эти языки используют оптимизацию HotSpot. ВМ очень хорошо отслеживается и поддается отладке.

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

ThreadLocals обычно не так широко известны как способ хранения состояния каждого потока.

Поскольку JDK 1.5 Java имеет чрезвычайно хорошо реализованные и надежные инструменты параллелизма, помимо блокировок, они находятся в java.util.concurrent, и особенно интересным примером является подпакет java.util.concurrent.atomic, который содержит потокобезопасные примитивы, реализующие сравнение -and-swap и может отображаться на фактические версии этих операций, поддерживаемые аппаратным обеспечением.

Как насчет ковариантных возвращаемых типов, которые используются с JDK 1.5? Это довольно плохо освещается, так как это несексуальное дополнение, но, как я понимаю, абсолютно необходимо для работы дженериков.

По сути, компилятор теперь позволяет подклассу сузить тип возвращаемого значения переопределенного метода до подкласса возвращаемого типа исходного метода. Итак, это разрешено:

class Souper {
    Collection<String> values() {
        ...
    }
}

class ThreadSafeSortedSub extends Souper {
    @Override
    ConcurrentSkipListSet<String> values() {
        ...
    }
}

Вы можете вызвать подкласс values метод и получить отсортированную потокобезопасный Set в String сек без необходимости вниз броска к ConcurrentSkipListSet .

Для большинства людей, которых я беру интервью у Java-разработчиков, позиции, помеченные блоками, очень удивительны. Вот пример:

// code goes here

getmeout:{
    for (int i = 0; i < N; ++i) {
        for (int j = i; j < N; ++j) {
            for (int k = j; k < N; ++k) {
                //do something here
                break getmeout;
            }
        }
    }
}

Кто сказал, что goto в Java это всего лишь ключевое слово? :)

Динамические прокси (добавленные в 1.3) позволяют вам определять новый тип во время выполнения, который соответствует интерфейсу. Пригодится на удивление много раз.

Совместное объединение в вариации параметра типа:

public class Baz<T extends Foo & Bar> {}

Например, если вы хотите взять параметр, который является как Comparable, так и Collection:

public static <A, B extends Collection<A> & Comparable<B>>
boolean foo(B b1, B b2, A a) {
   return (b1.compareTo(b2) == 0) || b1.contains(a) || b2.contains(a);
}

Этот надуманный метод возвращает истину, если две заданные коллекции равны или если одна из них содержит данный элемент, в противном случае - ложь. Следует отметить, что вы можете вызывать методы Comparable и Collection для аргументов b1 и b2.

На днях я был удивлен инициализаторами экземпляров. Я удалял некоторые методы с свернутым кодом и в итоге создал несколько инициализаторов экземпляров:

public class App {
    public App(String name) { System.out.println(name + "'s constructor called"); }

    static { System.out.println("static initializer called"); }

    { System.out.println("instance initializer called"); }

    static { System.out.println("static initializer2 called"); }

    { System.out.println("instance initializer2 called"); }

    public static void main( String[] args ) {
        new App("one");
        new App("two");
  }
}

При выполнении main метода отобразится:

static initializer called
static initializer2 called
instance initializer called
instance initializer2 called
one's constructor called
instance initializer called
instance initializer2 called
two's constructor called

Думаю, это было бы полезно, если бы у вас было несколько конструкторов и вам нужен был общий код.

Они также предоставляют синтаксический сахар для инициализации ваших классов:

List<Integer> numbers = new ArrayList<Integer>(){{ add(1); add(2); }};

Map<String,String> codes = new HashMap<String,String>(){{ 
  put("1","one"); 
  put("2","two");
}};

Разрешение методов и конструкторов в перечислениях меня удивило. Например:

enum Cats {
  FELIX(2), SHEEBA(3), RUFUS(7);

  private int mAge;
  Cats(int age) {
    mAge = age;
  }
  public int getAge() {
    return mAge;
   }
}

У вас даже может быть «постоянное тело конкретного класса», которое позволяет определенному значению перечисления переопределять методы.

Дополнительная документация здесь .

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

Collections.<String,Integer>emptyMap()

AsList метод java.util.Arrays позволяет хорошее сочетание, общих списков параметров методов и Autoboxing:

List<Integer> ints = Arrays.asList(1,2,3);

Не совсем особенность, но забавный трюк, который я недавно обнаружил на какой-то веб-странице:

class Example
{
  public static void main(String[] args)
  {
    System.out.println("Hello World!");
    http://Phi.Lho.free.fr

    System.exit(0);
  }
}

- допустимая программа на Java (хотя и выдает предупреждение). Если вы не понимаете почему, посмотрите ответ Грегори! ;-) Подсветка синтаксиса здесь тоже дает подсказку!

Мой любимый вариант: вывести все трассировки стека потоков в стандартный формат.

windows: CTRL- Breakв окне java cmd / console

unix: kill -3 PID

Использование этого ключевого слова для доступа к полям / методам содержащего класса из внутреннего класса. В приведенном ниже довольно надуманном примере мы хотим использовать поле sortAscending класса контейнера из анонимного внутреннего класса. Использование ContainerClass.this.sortAscending вместо this.sortAscending делает свое дело.

import java.util.Comparator;

public class ContainerClass {
boolean sortAscending;
public Comparator createComparator(final boolean sortAscending){
    Comparator comparator = new Comparator<Integer>() {

        public int compare(Integer o1, Integer o2) {
            if (sortAscending || ContainerClass.this.sortAscending) {
                return o1 - o2;
            } else {
                return o2 - o1;
            }
        }

    };
    return comparator;
}
}

Это не совсем «скрытые возможности» и не очень полезно, но в некоторых случаях может быть чрезвычайно интересным:
Класс sun.misc.Unsafe - позволит вам реализовать прямое управление памятью в Java (вы даже можете написать самомодифицирующийся код Java с помощью это, если вы много стараетесь):

public class UnsafeUtil {

    public static Unsafe unsafe;
    private static long fieldOffset;
    private static UnsafeUtil instance = new UnsafeUtil();

    private Object obj;

    static {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);

            unsafe = (Unsafe)f.get(null);
            fieldOffset = unsafe.objectFieldOffset(UnsafeUtil.class.getDeclaredField("obj"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    };
}

окончательную инициализацию можно отложить.

Он гарантирует, что даже при сложном потоке логики всегда будут установлены возвращаемые значения. Слишком легко пропустить регистр и случайно вернуть null. Это не делает невозможным возврат null, просто очевидно, что это сделано специально:

public Object getElementAt(int index) {
    final Object element;
    if (index == 0) {
         element = "Result 1";
    } else if (index == 1) {
         element = "Result 2";
    } else {
         element = "Result 3";
    }
    return element;
}

Несколько человек написали об инициализаторах экземпляров, вот вам хорошее применение:

Map map = new HashMap() {{
    put("a key", "a value");
    put("another key", "another value");
}};

Это быстрый способ инициализировать карты, если вы просто делаете что-то быстрое и простое.

Или использовать его для создания прототипа рамы быстрого поворота:

JFrame frame = new JFrame();

JPanel panel = new JPanel(); 

panel.add( new JLabel("Hey there"){{ 
    setBackground(Color.black);
    setForeground( Color.white);
}});

panel.add( new JButton("Ok"){{
    addActionListener( new ActionListener(){
        public void actionPerformed( ActionEvent ae ){
            System.out.println("Button pushed");
        }
     });
 }});


 frame.add( panel );

Конечно, можно злоупотреблять:

    JFrame frame = new JFrame(){{
         add( new JPanel(){{
               add( new JLabel("Hey there"){{ 
                    setBackground(Color.black);
                    setForeground( Color.white);
                }});

                add( new JButton("Ok"){{
                    addActionListener( new ActionListener(){
                        public void actionPerformed( ActionEvent ae ){
                            System.out.println("Button pushed");
                        }
                     });
                 }});
        }});
    }};

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

public void foo(String... bars) {
   for (String bar: bars)
      System.out.println(bar);
}

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

Не видел, чтобы кто-нибудь упоминал instanceof, реализованный таким образом, что проверка на null не требуется.

Вместо того:

if( null != aObject && aObject instanceof String )
{
    ...
}

просто используйте:

if( aObject instanceof String )
{
    ...
}

Вы можете использовать перечисления для реализации интерфейса.

public interface Room {
   public Room north();
   public Room south();
   public Room east();
   public Room west();
}

public enum Rooms implements Room {
   FIRST {
      public Room north() {
         return SECOND;
      }
   },
   SECOND {
      public Room south() {
         return FIRST;
      }
   }

   public Room north() { return null; }
   public Room south() { return null; }
   public Room east() { return null; }
   public Room west() { return null; }
}

РЕДАКТИРОВАТЬ: годы спустя ....

Я использую эту функцию здесь

public enum AffinityStrategies implements AffinityStrategy {

https://github.com/peter-lawrey/Java-Thread-Affinity/blob/master/src/main/java/vanilla/java/affinity/AffinityStrategies.java

Используя интерфейс, разработчики могут определять свои собственные стратегии. Используя enum средства, я могу определить коллекцию (из пяти) встроенных.

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

new Object() {
  void foo(String s) {
    System.out.println(s);
  }
}.foo("Hello");

Методы доступа к свойствам Java Bean не обязательно должны начинаться с «get» и «set».

Даже Джош Блох ошибается в Effective Java.

При работе в Swing мне нравится скрытая Ctrl- Shift- F1функция.

Он выгружает дерево компонентов текущего окна.
(Предполагая, что вы не связали это нажатие клавиши с чем-то другим.)

Подстановочные знаки пути к классам начиная с Java 6.

java -classpath ./lib/* so.Main

Вместо того

java -classpath ./lib/log4j.jar:./lib/commons-codec.jar:./lib/commons-httpclient.jar:./lib/commons-collections.jar:./lib/myApp.jar so.Main

См. http://java.sun.com/javase/6/docs/technotes/tools/windows/classpath.html