27 KiB
Java
Функция main
package org.example;
public class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
Сокращения InteliJ
- psvm - public static void main
- sout - Sytem.out.println()
- serr - System.err.println()
- I - for(Object object: ){}
- fori - for (int i = 0; i< ; i++) {}
- shift + shift - поиск по проекту
- ctrl + alt + t - сниппеты для блоков кода (циклы, if, switch, try-catch)
- alt + insert - сниппеты для класса
Строки
Строки неизменяемые (immutable) и не могут иметь наследников (final). Для изменения копии
// foo и bar - 1 объект в Pool (аля static)
String foo = "foo";
String bar = "foo";
// baz - объект в куче
String baz = new String("baz");
StringBuffer и StringBuilder
Данные типы - изменяемые строки с изменениями на месте. StringBuffer синхронизирует методы, поэтому медленее, но можно работать в многопотоке. StringBuilder быстрее, но методы не синхронизирует
// Можно передать строку в инициализатор, но не обязательно
StringBuffer sb = new StringBuffer();
sb.append("foo");
sb.append(5);
Методы StringBuffer и StringBuilder
- append (смотреть выше)
- delete(int start, int end)
- insert(int offeset, String str)
- replace(int start, int end, String str)
- reverse()
- substring(int start, int end) - создаст новую строку
- toString - перевести в строку
RegEx
RegEx - щаблон для поиска строки в тексте
Примеры RegEx
- "java" - только слово java подойдёт
- "\d{3}" - 3 цифры
Pattern для RegEx
Pattern - скомпилированный RegEx
Pattern p = Pattern.compile("java");
p = Pattern.compile("java", Pattern.CASE_INSENSETIVE);
Var
Var выбирает тип по типу данных, который мы присваеваем. Нужно инициализировать при объявлении
var x = 5;
Константы
В Java константы объявляются словом final
final int LIMIT = 5;
Массивы
Объявлять массивы можно разными способами
int nums[] = new int[] {10, 20};
int[] nums = {10, 20, 30};
Многомерный массив
int[][] nums = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
Параметры переменной длины
static void sum(int ...nums) {
int result = 0;
for(int n: nums) {
result += n;
}
System.out.println(result);
}
Все обязательные параметры до параметрвов переменной длины
Значения по умолчанию для параметров
Их нету!!!
Перегрузка методов
Перегрузка позволяет определять функции с одинаковым именем, но с разными типами и/или кол-вом параметров.
static int sum(int a, int b) {
return a + b;
}
static double sum(double a, double b) {
return a + b;
}
Если отличается только выходной тип, то останется только последняя имплементация
// Эту версию не получится вызвать
static int sum(int a, int b) {
return a + b;
}
// Будет вызываться эта версия
static double sum(int a, int b) {
return a + b;
}
Обработка ошибок
try-catch-finally
try {
int[] a = new int[3];
a[4] = 5;
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("Will always print this");
}
throw
throw new Exception("Very important exception! Don't you dare not handle it");
throws
Позволяет кинуть ошибку вверх по стаку
public static void main(String[] args) throws Exception {}
OOP
OOP - бяка, Java - OOP => Java - бяка
public class Foo {
int bar;
string baz;
void fooBar() {
System.out.println("FooBaz");
}
}
Модификаторы доступа
- public - везде
- private - только внутри класса
- protected - подклассы и сам класс
Если не указан, то применяется модификатор по умолчанию. Он делает переменную public в пределах данного пакета
Конструктор и инициализатор
public class Test {
int age;
int age2;
int age3;
// Блок - инициализатор
{
age = 5
}
// Конструктор
public Test(int age2, int age3_input) {
this.age2 = age2;
age3 = age3_input; // Такое не делать, ибо не красиво
}
}
Наследование
public class Foo {}
public class Bar extends Foo {}
Множественное наследование низя. Приватное не наследуется
Override
class Foo {
int foo() {
return 5;
}
}
class Bar extends Foo {
@Override
int foo() {
return 6;
}
}
Уровень видимости при Override не может понижаться. У переопределённого метода должен быть такой же интерфейс, как и у родителя
super
super позволяет обратиться к методам родительского класса
class Foo {
int foo() {
return 5;
}
}
class Bar extends Foo {
@Override
int foo() {
return super.foo();
}
}
final при наследовании
final запрещает наследование
Наследование конструктора
class Foo {
int a, b;
Foo(int a, int b) {
this.a = a;
this.b = b;
}
}
class Bar extends Foo {
int c;
Bar(int a, int b, int c) {
// Тут super должен быть сверху, иначе ошибка
super(a, b);
this.c = c;
}
}
instanceof
Позволяет проверить, создан ли объект на основе какого-то класса
class Foo {
int a, b;
Foo(int a, int b) {
this.a = a;
this.b = b;
}
}
class Bar extends Foo {
int c;
Bar(int a, int b, int c) {
// Тут super должен быть сверху, иначе ошибка
super(a, b);
this.c = c;
}
}
class Main {
public static void main() {
Bar bar = new Bar();
System.out.println(bar instanceof Foo);
}
}
Абстрактные классы
Абстрактные классы могут иметь абстрактные методы (без имплементации), но от них низя создать объект.
abstract class Car {
int speed;
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
abstract int brake();
}
class Sedan extends Car {
@Override
int brake() {
return 5;
}
}
public class Main {
public static void main(String[] args) {
Car car = new Car(); // Низя. Класс абстрактный
Sedan sedan = new Sedan();
}
}
Интерфейсы
Абстрактные классы для классов, которые имеют много общего, имеют близкую связть, а интерфейсы используются для тех, которые не имеют связи:
- Bird - абстрактный класс
- Flyable - интерфейс. Его могут имплементировать и птицы, и самолёты, и Карлсон
Отличия от классов:
- Нельзя создать экземпляр
- Не содержатся конструкторы
- Все методы абстрактные
- Все поля и static и final
- Интерфейс не расширяется классом, а реализуется
- Интерфейс может расширить множество интерфейсов
public interface Swimmable {
public void swim();
}
class Duck implements Swimmable {
public void swim() {
System.out.println("A duck is swimming");
}
}
Могут быть определения по умолчанию
public interface Swimmable {
default public void swim() {
System.out.println("Something is swimming")
}
}
class Duck implements Swimmable {}
Могут быть статические и приватные (доступные только внутри интерфейса) методы и константы
public interface Foo {
int VALUE = 5; // Подразумевается public static final т.е. публичная константная
static void foo() {
System.out.println("Foo");
}
private int bar(int a, int b) {
return a + b;
}
}
class Bar implements Foo {}
Интерфейсы могут расширять друг друга
interface Foo {
void foo();
}
interface Bar extends Foo {
default void bar() {
return;
}
}
class Baz implements Bar {
public void foo() {}
}
Интерфейсы могут быть вложены в классы
class Printer {
interface Printable {
void print();
}
}
class Journal implements Printer.Printable {
public void print() {
System.out.println("Priniting journal");
}
}
Классы обёртки
Обёртка - класс, хранящий внутри значение примитива. Эти классы содержат полезные методы и являются не изменяемыми
Автораспаковка, автоупаковка
int x = 5;
Integer y = x; // Автоупаковка
x = y; // Автораспаковка
Автоупаковка и автораспаковка не работает для массивов
Коллекции
Основные виды:
- Set
- HashSet
- TreeSet
- SortedSet
- List
- ArrayList
- LinkedList
- Vector
- Stack
- Map
- HashMap
- TreeMap
- SortedMap
- Hashtable
Итераторы
Позволяет перебирать значения коллекций. Может использоваться для неупорядоченных коллекций
Set<String> set = new HashSet<String>();
set.add("A");
set.add("B");
Iterator<String> iter = set.iterator();
while (iter.hasNext()) {
String text = iter.next();
System.out.println(text);
}
Map<String, String> map = new HashMap<String, String>();
map.put("first", "A");
Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, String> pair = iter.next();
String key = pair.getKey();
String value = pair.getValue();
System.out.println(key + ":" + value);
}
Можно использовать foreach
Set<String> set = new HashSet<String>();
set.add("A");
set.add("B");
for (String text : set) {
System.out.println(text);
}
ArrayList
ArrayList<Integer> nums = new ArrayList<int>();
nums.add(5);
nums.add(5);
nums.add(5);
nums.add(5);
nums.add(5);
System.out.println(nums.get(1));
System.out.println(nums.indexOf(5));
System.out.println(nums.contains(3));
nums.add(4, 3); // insert`ит на 4 индекс число 3
nums.set(4, 5); // Меняет число на 4 индексе на 5
System.out.println(nums.toString());
nums.clear();
nums.add(5);
nums.add(5);
nums.add(5);
Integer[] numss = nums.toArray(new Integer[0]);
nums = new ArrayList<>(Arrays.asList(numss));
Collections.sort(nums);
Ещё методы у Collections:
- min
- max
- reverse
- shuffle
- swap
- disjoint - если есть пересечение коллекций, то false, иначе true
Неизменяемый список
List<Integer> = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(1, 2, 3)));
LinkedList
LinkedList - двусвязный список
LinkedList<Integer> nums = new LinkedList<Integer>();
nums.add(5);
nums.add(5);
nums.add(5);
Особые методы:
- addFirst
- addLast
- peekFirst
- peekLast
- pollFirst - получить первый и удалить его (null, если пусто)
- pollLast
Vector
Vector - синхронизированный ArrayList, который всё хранит как Object. Синтаксис страшный.
Stack
Stack - LIFO
Методы:
- empty - возвращает bool
- peek
- pop
- push
- search - возвращает offset от вершины стека
Deque
Deque - двунаправленный стек с фиксированной длинной
Методы:
- addFirst
- addLast
- getFirst - без удаления
- getLast
- offerFirst
- offerLast
- peekFirst
- peekLast
- pollFirst - с удалением
- pollLast
ArrayDeque
ArrayDeque - двунаправленный стек с динамической длиной
Методы:
- addFirst
- addLast
- getFirst - без удаления
- getLast
- pollFirst - с удалением
- pollLast
HashSet
Аля Rust. Использует метод hashCode() для получения хеша значений
Методы:
- add
- remove
- contains
- size
- clear
- isEmpty
- iterator
Enum
enum Country {
CANADA, NETHERLANDS
}
enum Country2 {
CANADA("CAN"), NETHER("NTH"), ENGLAND
}
Работа с файлами
- FileWriter
- FileReader
В конце их нужно закрывать
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws Exception {
FileReader fr = new FileReader("Foo.txt");
Scanner scanner = new Scanner(fr);
ArrayList<String> words = new ArrayList<>();
while (scanner.hasNext()) {
words.add(scanner.next());
}
Collections.sort(words);
System.out.println(words);
}
}
Generic
class Account<T> { // Account<String> account = new Account<String>("FooBar");
private T id;
public int sum;
public Account(T id, int sum) {
this.id = id;
this.sum = sum;
}
public T getId() {
return id;
}
}
class Printer {
public static <T> void print(T[] items) { // Вызывать так: Printer.<String>print(new String[]{"a", "b"});
for(T item: items) {
System.out.println(item);
}
}
}
interface Acountable {
String getId();
}
class Account2 implements Acountable {
String id;
public <T>Account2(T id) { // Account account = new Account(5);
this.id = id.toString();
}
public String getId() {
return id;
}
}
class Transaction<T extends Account> { // T может быть только наследником Account
T account;
}
class Transaction2<T extends Acountable> { // T имплементирует Acountable
T account;
}
class Transaction3<T extends Account & Accountable> { // T имплементирует Accountable и наследует Account
T account;
}
Records
Записи или Records позволяют быстро содздавать классы, уменьшая количесво бойлерплейта. Записи автоматически определяют инициализатор, методы hashCode, toString и equals. Поля являются private и final и имеют одноимённые геттеры
record Person(String name, int age) { }
Можно добавить дополнительную логику в созданный конструктор
record Person(String name, int age) {
Person {
if(age < 1 || age > 110) {
age = 18;
}
}
}
Можно полностью переписать изначальный конструктор
record Person(String name, int age) {
Person(String name, int age) {
this.name = name;
if(age < 1 || age > 110) {
age = 18;
}
this.age = age;
}
}
Мы можем определять какие-то другие конструкторы, но они вызывать канонический конструктор
record Person(String name, int age) {
Person(String firstName, String lastName, int age) {
this(firstName + " " + lastName, age);
}
}
Можно также переопределить остальные методы
record Person(String name, int age) {
public String name() {
return "Mister " + name;
}
public String toString() {
return "What a fine gentleman we have here"
}
}
Ограничения record
Классы record не могут наследовать, быть наследованными и абстрактными, но могут имплементировать интерфейсы. Нельзя добавлять дополнительные нестатические пора и инициализаторы
record Person(String name, int age) {
static int minAge;
static { // Это статический инициализатор
minAge = 18;
}
}
Upcasting & Downcasting
class Person {}
class Employee {}
class Main {
public static void main(String[] args) {
Object bob = new Person(); // Upcasting
Person tom = new Employee(); // тоже upcasting
Person bob2 = (Person)bob;
}
}
Comparator & Comparable
import java.util.Comparator;
import java.util.TreeSet;
class Person implements Comparable<Person> {
private String name;
private int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
String getName() {
return name;
}
int getAge() {
return age;
}
// Отриц число, если меньше, 0, если равно, и полож число, если больше
public int compareTo(Person p) {
return name.compareTo(p.getName());
}
}
class PersonNameComparator implements Comparator<Person> {
public int compare(Person a, Person b) {
return a.getName().compareTo(b.getName());
}
}
class PersonAgeComparator implements Comparator<Person> {
public int compare(Person a, Person b) {
return a.getAge() - b.getAge();
}
}
class Main {
public static void main(String[] args) {
Comparator<Person> pcomp = (new PersonNameComparator()).thenComparing(new PersonAgeComparator());
TreeSet<Person> people = new TreeSet<Person>(pcomp);
people.add(new Person("Tom", 10));
people.add(new Person("Tam", 12));
people.add(new Person("Tim", 13));
people.add(new Person("Bill", 40));
people.add(new Person("Bob", 15));
for(Person p : people) {
System.out.println(p.getName());
}
}
}
Лямбда
Лямбда представляет набор инструкций,которые можно выделить в отдельную переменную
public class Main {
public static void main(String[] args) {
Operation op = (x, y) -> x + y;
Operation op2 = (int x, int y) -> x - y;
int result = op.calculate(10, 20);
System.out.println(result);
System.out.println(op.calculate(10, 20));
}
}
interface Operation {
int calculate(int x, int y);
}
Альтернативные формы:
-
() -> 30 + 30
-
n -> n * n
Лямбда функции могут возвращать void
interface Printer {
void print(String s);
}
class Main {
public static void main(String[] args) {
Printer p = (s) -> System.out.println(s);
}
}
Переменные, которые используются в лямбде нельзя менять
Блоки кода в лямбда-функциях
public class Main {
public static void main(String[] args) {
Operation op = (int x, int y) -> {
if(x < 0) {
x = -x;
}
return x + y;
};
}
}
interface Operation {
int calculate(int x, int y);
}
Обобщённые лямбды
public class Main {
public static void main(String[] args) {
Operation<Integer> op = (x, y) -> {
if(x < 0) {
x = -x;
}
return x + y;
};
}
}
interface Operation<T> {
T calculate(T x, T y);
}
Ссылки на метод, как параметр методов
interface Operation {
int calculate(int x, int y);
}
class Operations {
static int Add(int x, int y) {
return x + y;
}
}
class Main {
public static void main(String[] args) {
Operation op = Operations::Add;
}
}
Также можно ссылаться на методы объекта, через переменная::метод, и на конструктор, через класс::new. Лямбды также можно возврощать
Встроенные функцианальные интерфейсы
- Predicate<T> - boolean test(T t)
- BinaryOperator<T> - T apply(T t1, T t2)
- UnaryOperator<T> - T apply(T t)
- Function<T, R> - R apply(T t)
- Consumer<T> - void accept(T t)
- Supplier<T> - T get()
Java.Util
Класс Locale
Локали - боль... страдания... C++
Locale.getDefault() чтобы получить текущую
Date
Date - штука для работы с датами. Можно использовать для форматирования с помощью Locale
Calendar & GregorianCalendar
Calendar - абстрактный класс, а GregorianCalendar - имплементация. Он также держит часы, минуты, секунды. Класс DateFormat для красивого вывода
TimeZone & SimpleTimeZone
Calendar - абстрактный класс, а GregorianCalendar - имплементация. Он также держит часы, минуты, секунды. Нужны для работы с часовыми поясами
UUID
UUID - класс для работы с UUID
UUID id = UUID.randomUUID();
StringTokenizer
StringTokenizer нужен для разделения строк на токены, используя данный разделитель (по умолчанию пробел)
Android Studio
Устройство платформы Android
- Базовый уровень (Linux Kernel) - firmware
- Библиотеки и среда исполнения (Libraries & Android Runtime)
- Каркас приложений (Application Framework)
- Уровень приложений (Applications)
Комплекты разработчика
- JDK (Java Development Kit) - комплект разработчика на Java. Включает компилятор, библиотеки, примеры, документацию, утилиты и исполнительную среду
- SDK (Software Development Kit) - утилиты для создания и тестирования приложений
- SDK Manager - инструмент для заргузки компонентов Android SDK
- Android Emulator - эмулирует телефон на компьютере
- AVD Manager - графический интерфейс для создания виртуальных Android устройст
- Android Debig Bridge - управление состоянием эмулятора или реального устройства, подключённого к компьютеру
Структура Android приложения
- Gen файлы генерируются Java. Являются обязательным компонентом
- AndroidManifest.xml - файл манифеста предоставляет системе лсновную информацию о программе
- Src - каталог с исходным компонентом
- Assets - произвольное собрание каталогов и файлов
- Res - катагол с ресурсами прилодения. Там подкапки drawable, anum, layout, menu, values, xml и raw
Инициализация объектов Activity
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import com.example.myapplication.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
int counter = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);
binding.textView.setText("0");
binding.textView.setTextSize(33);
binding.textView.setTextColor(Color.RED);
binding.button.setOnClickListener((foo) -> {
counter += 1;
binding.textView.setText(String.valueOf(counter));
});
}
}
Переключение Activity
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
Fragments
Fragment - подобие activity, но одно activity может содержать несколько фрагментов.
Для взаимодействия фрагментов используется FragmentManager, а для удаления, добавления и замены FragmentTransaction
Основные методы FragmentManager:
- findFragmentById(int id)
- findFragmentByTag(String tag)
Методы FragmentTransaction:
- add
- remove
- replace
- hide
- show
- detach - открепляет от GUI, но экземпляр сохраняется
- attach - обратный метод detach
Для получения экземляра FragmentTransaction нужно вызвать FragmentManager.beginTransaction. После транзакции вызывается commit
Адаптеры
- ArrayAdapter<T>
- ListAdapter
- SpinnerAdapter
- SimpleAdapter
LayoutInflater
Позволяет из содержимого layout файла создать View элемент