Java Порядок инициализации полей и блоков при наследовании

Порядок инициализации полей и блоков при наследовании

Есть суперкласс А, от данного суперкласса наследуется подкласс B:

public class A {
	 
    {
        System.out.println("A class. No static block 1");
    }
 
    {
        System.out.println("A class. No static block 2");
    }
 
    {
        System.out.println("A class. No static block 3");
    }
 
    static {
        System.out.println("A class. Static block 1");
 
    }
 
    static {
        System.out.println("A class. Static block 2");
 
    }
    public static String a1 = psv("a1");
     
    public String a11 = pnsv("a11");
 
    static {
        System.out.println("A class. Static block 3");
 
    }
    public static String a2 = psv("a2");
 
    private static String psv(String a) {
        System.out.println("A class. Static perem " + a);
        return a;
 
    }
 
    private String pnsv(String a) {
        System.out.println("A class. No static perem " + a);
        return a;
 
    }
     
    public A() {
    	System.out.println("A class. Constructor");
    }
 
 
    public String a22 = pnsv("a22");
 
    public static String a3 = psv("a3");
     
    {
        System.out.println("A class. No static block 4");
    }
     
    public String a33 = pnsv("a33");
 
}

И класс B, который наследуется от класса A:

public class B extends A{
	private int b = bb(20);

	public B(int b) {	
		this.b = b;
	}
	
	private int bb(int x) {
		System.out.println("B class. No static perem " + x);
		return 0;
	}

	public B() {
		System.out.println("B class. Constructor");
	}
	
	static {
		System.out.println("B class. Static block 1");
	}
	
	
}

Вызов конструктора у класса B:

public class Test {	
	public static void main(String[] args) {
		new B();
	
	}
}

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

A class. Static block 1
A class. Static block 2
A class. Static perem a1
A class. Static block 3
A class. Static perem a2
A class. Static perem a3
B class. Static block 1
A class. No static block 1
A class. No static block 2
A class. No static block 3
A class. No static perem a11
A class. No static perem a22
A class. No static block 4
A class. No static perem a33
A class. Constructor
B class. No static perem 20
B class. Constructor

Т.е. порядок такой:
1. Статические блоки и статические поля в порядке объявления суперкласса(А)
2. Статические блоки и статические поля в порядке объявления подкласса(В)
3. Не статические блоки и не статические поля в порядке объявления суперкласса(А)
4. Конструктор суперкласса(А)
5. Не статические блоки и не статические поля в порядке объявления подкласса(B)
6. Конструктор подкласса(B)

Реклама

Java.Порядок инициализации полей и блоков БЕЗ наследования.

Рассмотрим простенький пример при инициализации полей и блоков (без наследования)
Есть класс:

package inizialization;

public class A {

	{
		System.out.println("No static block 1");
	}

	{
		System.out.println("No static block 2");
	}

	{
		System.out.println("No static block 3");
	}

	static {
		System.out.println("Static block 1");

	}

	static {
		System.out.println("Static block 2");

	}
	public static String a1 = psv("a1");
	
	public String a11 = pnsv("a11");

	static {
		System.out.println("Static block 3");

	}
	public static String a2 = psv("a2");

	private static String psv(String a) {
		System.out.println("static perem " + a);
		return a;

	}

	private String pnsv(String a) {
		System.out.println("no static perem " + a);
		return a;

	}
	
	public A() {
		System.out.println("Вызов конструктора");
	}


	public String a22 = pnsv("a22");

	public static String a3 = psv("a3");
	
	{
		System.out.println("No static block 4");
	}
	
	public String a33 = pnsv("a33");

}

Вызовем конструктор:

package inizialization;

public class Main {
	
	public static void main(String[] args) {
		new A();		
	}
}

На консоль будет выведено:

Static block 1
Static block 2
static perem a1
Static block 3
static perem a2
static perem a3
No static block 1
No static block 2
No static block 3
no static perem a11
no static perem a22
No static block 4
no static perem a33
Вызов конструктора

Т.е. при вызове конструктора сначала инициализируются
1. Статические поля и статические блоки(в порядке объявления в классе)
2. Нестатические поле и нестатичиские блоки (в порядке объявления в классе)
3. Конструтор

Вызовем два раза конструктор класса A:

package inizialization;

public class Main {
	
	public static void main(String[] args) {
		new A();
		new A();		
	}
}

На консоль будет выведено:

Static block 1
Static block 2
static perem a1
Static block 3
static perem a2
static perem a3
No static block 1
No static block 2
No static block 3
no static perem a11
no static perem a22
No static block 4
no static perem a33
Вызов конструктора
No static block 1
No static block 2
No static block 3
no static perem a11
no static perem a22
No static block 4
no static perem a33
Вызов конструктора

Т.е. при вызове двух конструкторов сначала один раз (именно один раз) инициализируются
статичские поля и статические блоки, потом инициализируются нестатические поля и нестатические блоки, потом конструктор,
потом опять нестатические поля и нестатические блоки, потом конструктор.
Важно, что статические поля и статичекские блоки инициализируются ровно один раз.

Теперь рассмотрим пример, где мы просто вызываем статичекий метод (т.е. через ИМЯ_КЛАССА.ИМЯ_СТАТИЧЕСКОГО_МЕТОДА):

package inizialization;

public class Main {
	
	public static void main(String[] args) {
		String test =  A.a1;
	}
}

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

Static block 1
Static block 2
static perem a1
Static block 3
static perem a2
static perem a3

Т.е. при вызове статического метода инициализируются ТОЛЬКО статические поля и блоки и только 1 раз, т.е.даже если мы напишем:

String test =  A.a1;
String test2 =  A.a1;

то вывод на консоль не поменяется

Java 8 Добавить дни к дате, исключая выходные.

Часто бывает задача, что нам надо к дате прибавить несколько дней. Но мы должны игнорировать выходные(Суббота, Воскресенье).
Использую новое API для работы с датами, это делается примерно так:

private static final String FORMAT_DATE = "dd.MM.yyyy";
	
public static DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(FORMAT_DATE);
	    
	    
public static String addDaysWithoutWeekends(String date, int countDays) {
    if (countDays <= 0) {
        return date;
    }

    LocalDate resultDate = LocalDate.parse(date, dateFormatter);
    int addedDays = 0;
    while (addedDays < countDays) {
    	resultDate = resultDate.plusDays(1);
        if (!(resultDate.getDayOfWeek() == DayOfWeek.SATURDAY ||
       		resultDate.getDayOfWeek() == DayOfWeek.SUNDAY)) {
                addedDays++;	           
        }
     }

    return dateFormatter.format(resultDate);
}

Если выполнить код:

System.out.println(addDaysWithoutWeekends("31.01.2018", 4));

То вывод на консоль будет:
06.02.2018

Java8. Класс Files метод walk

Иногда есть простенькие задачи, зайти в некий каталог и перебрать там все файлы, оставив только xml.
В Java8 добавили метод walk для перебора файлов

List<Path> paths =  Files.walk(Paths.get(PATH_TO_FILES)).filter(Files::isRegularFile).filter(p->p.toString().endsWith(".xml")).collect(Collectors.toList());

Можно чуть усложнить задачу.
Например нам нао получить список xml файлов в папке, которые содержат какую-то строку.

public static List<File> listFiles(String path, String fileEndsWith, String fileContains) throws IOException {
		return Files.walk(Paths.get(path)).filter(Files::isRegularFile).filter(p->p.toString().endsWith(fileEndsWith)).
				filter(p->{					
					try {
						String content = new String(Files.readAllBytes(p));
						if (content.contains(fileContains)) {
							return true;
						}
					} catch (Exception e) {						
						e.printStackTrace();						
					}
					return false;			
			}).map(Path::toFile).collect(Collectors.toList());
	}

Java8. StreamAPI. Метод peek

В стримах есть классный метод peek
Он служит для двух целей:
а)отладка
б)изменение элементов стрима(т.е. peek возвращает тоже стрим, но применяет функцию к
каждому элементу в стриме)

Например, есть некая коллекция:

public static List<Product> productList = Arrays.asList(new Product("Lipton Yellow Label", 131),
			new Product("English Breakfast", 170), new Product("Lipton Green Label", 180),
			new Product("Gold tea", 1000), new Product("Green tea", 199));

Выполним следующий код:

System.out.println(productList);
		System.out.println("==================");
		productList.stream()
				.peek(p->p.setPrice((int) (p.getPrice()*0.8)))
				.collect(Collectors.toList());
		System.out.println( productList);

Здесь мы все цены умножили на 0.8

Получаем вывод на консоль:

[Product [productName=Lipton Yellow Label, price=131], Product [productName=English Breakfast, price=170], Product [productName=Lipton Green Label, price=180], Product [productName=Gold tea, price=1000], Product [productName=Green tea, price=199]]
==================
[Product [productName=Lipton Yellow Label, price=104], Product [productName=English Breakfast, price=136], Product [productName=Lipton Green Label, price=144], Product [productName=Gold tea, price=800], Product [productName=Green tea, price=159]]

Как видим цена уменьшилась на 20%

Java8. Метод partitioningBy

У класса Collectors есть метод partitioningBy. Он разбивает коллекцию на две части.
В первую часть попадают элементы, которые удовлетворяет условию, а во вторую — которые не удовлетворяют

Есть простой POJO класс Product:

package org.example.sreams;

public class Product {
	
	private String productName;
	
	private int price;
	
	public Product(String productName, int price) {
		super();
		this.productName = productName;
		this.price = price;
	}
	public String getProductName() {
		return productName;
	}
	public void setProductName(String productName) {
		this.productName = productName;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	@Override
	public String toString() {
		return "Product [productName=" + productName + ", price=" + price + "]";
	}
	
	
}

Теперь главный класс:

package org.example.sreams;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {

	private final static int elitePrice = 1000;

	public static List<Product> productList = Arrays.asList(new Product("Lipton Yellow Label", 131),
			new Product("English Breakfast", 170), new Product("Lipton Green Label", 180),
			new Product("Gold tea", 1000), new Product("Green tea", 200));

	public static void main(String args[]) {
		System.out.println("==================");
		Map<Boolean, List<Product>> priceOverMax = productList.stream()
				.collect(Collectors.partitioningBy(tea -> tea.getPrice() >= elitePrice));
		System.out.println(priceOverMax);

	}
}

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

==================
{false=[Product [productName=Lipton Yellow Label, price=131], Product [productName=English Breakfast, price=170], Product [productName=Lipton Green Label, price=180], Product [productName=Green tea, price=200]], true=[Product [productName=Gold tea, price=1000]]}

Здесь мы разбили коллекцию на 2 части:
В первую часть(т.е. где true) попали данные где цена больше или равна elitePrice(т.е. 1000) — подходит только один товар,
во вторую часть (т.е. где false) попали данные где цена меньше 1000.

Чтобы взять данные где условие выполнилось надо написать:
priceOverMax.get(true)
соответственно, где условие не выполнилось :
priceOverMax.get(false)

Java. Фильтрация Enum

Часто приходится работать с Enum. Во время работы с Enum иногда приходится его фильтровать.

У нас есть Enum UserTypeEnum.
Для фильтрации данных в можно добавить в Enum такой метод, который принимает предикат.

public static List<UserTypeEnum> userTypeFilter(Predicate<UserTypeEnum> p) {
		List<UserTypeEnum> userTypeEnum = new ArrayList<>(Arrays.asList(UserTypeEnum.values()));
		return userTypeEnum.stream().filter(p).collect(Collectors.toList());
}

В итоге код Enum будет такой:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public enum UserTypeEnum {
	// admins group
	ADMIN(true, true, true), 
	MAIN_MODERATOR(true, true, true),
	MODERATOR(true, true, false),
	// users group
	BUYER(false, false, false), 
	SELLER(false, true, false);

	private boolean isEditUserComments;
	private boolean isEditModeratorComments;
	private boolean isAddProduct;
	
	public static List<UserTypeEnum> userTypeFilter(Predicate<UserTypeEnum> p) {
		List<UserTypeEnum> userTypeEnum = new ArrayList<>(Arrays.asList(UserTypeEnum.values()));
		return userTypeEnum.stream().filter(p).collect(Collectors.toList());
	}

	private UserTypeEnum(boolean isEditUserComments, boolean isEditModeratorComments, boolean isAddProduct) {
		this.isEditUserComments = isEditUserComments;
		this.isEditModeratorComments = isEditModeratorComments;
		this.isAddProduct = isAddProduct;
	}

	public boolean isEditUserComments() {
		return isEditUserComments;
	}

	public boolean isEditModeratorComments() {
		return isEditModeratorComments;
	}

	public boolean isAddProduct() {
		return isAddProduct;
	}
	
	

}

Вызов такой:

List<UserTypeEnum> addProd = UserTypeEnum.userTypeFilter(u -> u.isAddProduct());
System.out.println(addProd);
List<UserTypeEnum> dontAddProd = UserTypeEnum.userTypeFilter(u -> !u.isAddProduct());
System.out.println(dontAddProd);

Вывод на консоль:
[ADMIN, MAIN_MODERATOR]
[MODERATOR, BUYER, SELLER]

Java8 StreamAPI для группировки (groupingBy)

Нужно сделать группировку по полю brand
Раньше группировка делалась достаточно сложно:

public Map<String, List<Product>> groupByBrand() {

	Map<String, List<Product>> result = new HashMap<>();

	for (Product product : prodCollection) {
		if (result.containsKey(product.getBrand())) {
			result.get(product.getBrand()).add(product);
		} else {
			ArrayList<Product> products = new ArrayList<>();
			products.add(product);
			result.put(product.getBrand(), products);

		}
	}
		
		

	return result;
}

Но с приходом Java8 стало намного проще:

public Map<String, List<Product>> groupByBrandSteramApi() {
	return products().collect(Collectors.groupingBy(Product::getBrand));	
}

Java8. Метод join, StringJoiner, joining

В класс String добавили метод join, который служит для соединения строк с заданным разделителем.

String s = String.join("-", "2017", "08", "23");
System.out.println(s);

Output:
2017-08-23

Также можно передавать коллекцию:

List<String> cities  = Arrays.asList("Minsk", "Moscow" , "Kiev", "Ljubljana");
String citiesWithComma = String.join("," , cities);
System.out.println(citiesWithComma);

Output:
Minsk,Moscow,Kiev,Ljubljana

Добавили также специальный класс StringJoiner. Тут мы в конструктор просто передали разделитель запятую:

StringJoiner joiner = new StringJoiner(",");
joiner.add("Minsk");
joiner.add("Moscow");
joiner.add("Kiev");
joiner.add("Ljubljana");
System.out.println(joiner);

Output:
Minsk,Moscow,Kiev,Ljubljana

Благо, метод add возвращает this, а не void. Поэтому проще написать так:

StringJoiner joiner2 = new StringJoiner(",");
joiner2.add("Minsk")
.add("Moscow")
.add("Kiev")
.add("Ljubljana");
System.out.println(joiner2);

Output:
Minsk,Moscow,Kiev,Ljubljana

Также в конструктор в StringJoiner можно передавать не только разделитель, но и начало и
конец строки:

StringJoiner joiner3 = new StringJoiner(",", "[", "]");
joiner3.merge(joiner2);
System.out.println(joiner3);

Output:
[Minsk,Moscow,Kiev,Ljubljana]

Здесь, чтобы писать меньше кода я соединил joiner3 и joiner2 с помощью метода merge.

Еще в StringJoiner есть метод length — возвращает длину строки и setEmptyValue — т.е. если в joiner ничего не добавлено, то
там хранится введенное значение.

Больше никаких методов в StringJoiner нет.

Также у класса Collectors есть метод joining.
Тут тоже все примитивно(линк на гитхаб https://github.com/VictorSem/ProductJava8/blob/master/ProductJava8/src/main/java/org/example/main/MainClasss.java):

String testJoining = pc.products().map(x->x.getBrand()).distinct().collect(Collectors.joining(",", "[", "]"));
log.info(testJoining);

Output:
[Наши традиции,Ахмад,Беседа,Lipton]

Java8. Match функции

Существуют 3 булевы функции:
anyMatch — возвращает true, если существует лишь хоть ОДИН элемент в списке, удовлетворяющий условию.

noneMatch — возвращает true, если НЕ существует ни одного элемента в списке, удовлетворяющего условию.

allMatch — возвращает true, если ВСЕ элементы в списке, удовлетворяют условию.

Код :

public boolean isAnyProductPriceGreaterOrEqual(Integer productPrice) {
	return products().anyMatch(p -> p.getPrice() >= productPrice);
}
	
public boolean isNoneProductPriceGreaterOrEqual(Integer productPrice) {
	return products().noneMatch(p -> p.getPrice() >= productPrice);
}
	
public boolean isAllProductPriceGreaterOrEqual(Integer productPrice) {
	return products().allMatch(p -> p.getPrice() >= productPrice);
}

Весь код на гитхаб:
https://github.com/VictorSem/ProductJava8