четверг, 8 декабря 2011 г.

Wrapper pools

В Java для более эффективного использования памяти используются пулы для хранения одних и тех же значений. Например, если создать две строковые переменные одинакового содержания без использования ключевого слова new, то при создании второй переменной ей будет присвоена ссылка на первую. Тоже касается, например, объектов Integer, но только для значений от -128 до 127. Но строки, созданные во время выполнения не будут являться одним объектом, за искобчением случая использования метода intern()


public class StringTest {
    public static final void main(String[] args) {
        String a = "Test string";
        String b = "Test string";
        String c = new String("Test string");
        
        String d = "Test ";
        String e = "string";
        
        System.out.format(
            "%s %s %s %s",
            a == b, a == c, a == (d + e), a == (d + e).intern()
        );
    }
}
/**
 * Output: true false false true
 */

среда, 7 декабря 2011 г.

Финализация потока-демона

Т.к. поток-демон завершает свою работу внезапно, в момент, когда закончил свою работу последний поток не-демон, возникает проблема с нормальным завершением работы. В следующем примере текст в блоке finally не будет выведен на консоль.

public class DeamonTest implements Runnable {   
    public void run() {
        try {
            System.out.println("Trying");
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            System.out.println("InterruptedException");
        } finally {
            System.out.println("Never prints");
        }
    }
    
    public static void main(String[] args) {
        Thread t = new Thread(new DeamonTest());
        t.setDaemon(true);
        t.start();
    }
}
/**
 * Output: Trying
 */

Локальные классы и их модификаторы

Локальные классы не могут быть объявлены как public/private/protected/static, т.к. эти модификаторы предназначены только для членов класса

вторник, 6 декабря 2011 г.

Немного про сериализацию

Ключевое слово transient используется для полей, которые не нужно сериализовывать.

Значения статических полей не сохраняются при сериализации.

Если в иерархии объектов, при их сериализации, попадется объект - не serializable - выскочит exception.

Если в одном файле будет несколько объектов, имеющих общую ссылку, то при десереализации ссылка так же будет одна. Если сериализовать один и тот же объект в разные места, то при десериализации они не будут являться одним и тем же объектом.

Method overloading

При передаче параметра одному из перегруженных методов всегда выбирается наиболее специфичный, например:

public class Overload {
      public void method(Object o) {
        System.out.println("Object");
      }
      public void method(java.io.FileNotFoundException f) {
        System.out.println("FileNotFoundException");
      }
      public void method(java.io.IOException i) {
        System.out.println("IOException");
      }
      public static void main(String args[]) {
        Overload test = new Overload();
        test.method(null);
      }
}
/**
 * Output: FileNotFoundException
 */
Если среди перегруженных методов есть те, которые принимают объекты, находящиеся на одном уровне иерархии, код не скомпилируется:

public class Overload {
    public void method(Object o) {
        System.out.println("Object");
      }
      public void method(String s) {
        System.out.println("String");
      }
      public void method(StringBuffer sb) {
        System.out.println("StringBuffer");
      }
      public static void main(String args[]) {
        Overload test = new Overload();
        test.method(null); //The method method(Object) is ambiguous for the type Overload
      }
}
По мотивам http://habrahabr.ru/blogs/java/111189/

понедельник, 5 декабря 2011 г.

Исключения и переопределение метода

Исключения и переопределение метода — 1

Что будет выведено в результате выполнения этого кода?

class A {
    public void print() throws Exception {
        throw new Exception();
    }
}

class B extends A {
    public void print() {
        System.out.println("B");
    }
}

public class Main {

    public static final void main(String[] args) {
        B b = new B();
        b.print();
    }

}

1. B
2. Ничего
3. Ошибка компиляции
4. Exception

Ответ:
Переопределяющий метод не должен бросать новое или более широкое по классу исключение. Не бросать его вообще он может. Так что код скомпилируется и выведет B.

Исключения и переопределение метода — 2

Что будет выведено в результате выполнения этого кода?

class A {
    public void print() throws Exception {
        throw new Exception();
    }
}

class B extends A {
    public void print() {
        System.out.println("B");
    }
}

public class Main {

    public static final void main(String[] args) {
        A a = new B();
        a.print();
    } 

}

1. B
2. Ничего
3. Ошибка компиляции
4. Exception

Ответ:
3. Ошибка компиляции.
Так как мы в классе A объявлено исключение, а в main(...) мы его не обрабатываем. Тип возвращаемого значения (который может быть не таким, как в суперклассе, ведь есть covariant return) и выбрасываемые исключения проверяются компилятором по типу ссылки.

Источник: http://habrahabr.ru/blogs/java/131198/

instanceof

Что будет выведено в результате выполнения этого кода?

class A {
}

class B extends A {
}

class C extends B {
}

class D {
}

public class Main {

    public static final void main(String[] args)  {
        B b = new C();
        A a = new C();
        D d = new D();
        System.out.println(b instanceof A);
        System.out.println(a instanceof B);
        System.out.println(d instanceof C);
    }
}
1. true true false
2. true false false
3. Ошибка компиляции

Ответ:
3. Ошибка компиляции. Так произойдет, потому что D и C находятся на разных ветках иерархии и не приводимы друг к другу.

Источник: http://habrahabr.ru/blogs/java/131198/

пятница, 2 декабря 2011 г.

Замечательный класс java.util.prefs.Preferences

Класс java.util.prefs.Preferences позволяет сохранять небольшие объемы данных, которые затем можно получать при последующих запусках программы. Возможно, будет полезно его использовать в некоторых случаях вместо сериализации объектов.


public class PreferencesTest {
    private static Preferences pref = 
        Preferences.userNodeForPackage(PreferencesTest.class);
    
    public PreferencesTest() {
        int launchesCount = pref.getInt("launchesCount", 0);
        pref.putInt("launchesCount", ++launchesCount);
        System.out.format(
            "Hello, %s! Your app launches count is %d%n", 
            getName(), 
            launchesCount
        );
    }
    
    public static void main(String[] args) {
        PreferencesTest prefTest1 = new PreferencesTest();
        prefTest1.setName("Sub Zero");
        new PreferencesTest();
        new PreferencesTest();
    }
    
    public void setName(String name) {
        pref.put("name", name);
    }
    
    public String getName() {
        return pref.get("name", "Guest");
    }
}
/**
 * Hello, Guest! Your app launches count is 1
 * Hello, Sub Zero! Your app launches count is 2
 * Hello, Sub Zero! Your app launches count is 3
 */

@Override

Использовать @Override аннотацию для методов, которые переопределяют методы супер классов. Это позволяет сразу избежать опечаток и повышает читаемость кода (позволяет сразу понять, что у супер класса есть такой же метод не открывая родительский класс).

Правильно определять обертки примитивных типов


//медленно
Integer i = new Integer(100);
Long l = new Long(100);
String s = new String("A");
String s1 = 8 + "";

//быстро
Integer i = Integer.valueOf(100);
Long l = 100L; //это тоже самое что Long.valueOf(100L);
String s = "A";
String s1 = String.valueOf(8);

четверг, 1 декабря 2011 г.

Всегда возвращать пустые коллекции и массивы, вместо null.

Это сэкономит время на дальнейшей проверке значения на null в местах использования.
Для коллекций существуют специальные методы:
Collections.emptyList();
Collections.emptyMap();
Collections.emptySet();

Статические поля родителей являются общими для наследников


class T1 extends T {}

class T2 extends T {}

class T {
    public static int i;
}

public class Test {
    public static void main(String[] args) {
        T1.i = 5;
        T2.i = 3;
        System.out.format("%d = %d", T1.i, T2.i);
    }
}

/**
 * Output: 3 = 3
 */

Избегать конкатенации строк оператором +

Избегать конкатенации строк оператором +. При каждом использовании данного оператора создается новый объект.


Long l1 = System.currentTimeMillis();
String test = new String();
for (int i = 0; i < 100000; i++) {
    test += "d";
}
System.out.println(System.currentTimeMillis()-l1);

Long l2 = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100000; i++) {
    sb.append("d");
}
System.out.println(System.currentTimeMillis()-l2);
/**
 * Output:
 * 10728
 * 10
 */

Использование нестатических блоков инициализации

При помощи нестатических блоков инициализации можно элегантно инициализировать коллекцию:
Map map = new HashMap() {{
    put("собака",  "барбос");
    put("попугай", "кеша");
    put("кошка",   "мурка");
}};

Static methods cannot be overriden

В Java статические методы не могут быть переопределены наследниками

Сериализация

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

java.io.NotSerializableException выбрасываться не будет в случае B b = null, т.к. объект не был инициализирован.


public class Test {
    public static void main(String[] args) throws FileNotFoundException, 
    IOException, ClassNotFoundException {
        ObjectOutputStream out = 
            new ObjectOutputStream(new FileOutputStream("testfile"));
        out.writeObject(new C(1));
        
        ObjectInputStream in = 
            new ObjectInputStream(new FileInputStream("testfile"));
        in.readObject();
    }
}

class B {
    public B() {
        System.out.print("B");
    }
    public B(int i) {
        System.out.print("1");
    }
}

class C extends B implements Serializable {
    B b = null;
    public C() {
        System.out.print("C");
    }
    public C(int i) {
        super(i);
        System.out.print("2");
    }
}
/**
 * Output: 12B
 */

Хороший сайт для подготовки в экзамену 1Z0-851 Java Standard Edition 6 Programmer Certified Professional Exam

http://www.certpal.com/ExamWeb/content/logon.do#panel-8