<dependency>
<groupId>org.apache.commons</groupId> (1)
<artifactId>commons-csv</artifactId> (2)
<version>1.14.1</version> (3)
</dependency>@inponomarev
Иван Пономарёв, КУРС/МФТИ
Современный интернет адрес: company.com/product (com — top level domain, company — домен внутри com).
Более логичный вариант: com.company/product — постоянное движение от общего к частному — проиграл на заре Интернета по историческим причинам.
Reverse domain name notation — ключевая идея для именования пакетов и библиотек в Java, основанная на уникальности и понятном владении доменными именами.
Reverse domain notation + иерархическая система, которую можно модерировать внутри организации:
edu.phystech.foo
edu.phystech.foo.bar
Каждый .java-файл начинается с объявления пакета:
package edu.phystech.hello;
В корне пакета может быть файл package-info.java, не содержащий код, а только JavaDoc-описание над ключевым словом package.
<Имя пакета>.<имя класса> задаёт полный идентификатор любого класса, доступного в исходном коде или через библиотеки (например, edu.phystech.hello.App)
Пакеты физически — это дерево папок: edu/phystech/hello. Таким образом, в папке edu возможны подпапки edu/phystech и edu/berkley.
Пакеты логически — это плоский список. Два разных пакета полностью независимы, даже если визуально один является «подпакетом» другого.
Пример включения зависимости в Maven:
<dependency>
<groupId>org.apache.commons</groupId> (1)
<artifactId>commons-csv</artifactId> (2)
<version>1.14.1</version> (3)
</dependency>| 1 | домен огранизации в reverse notation (https://commons.apache.org/) |
| 2 | имя проекта |
| 3 | версия релиза, например в формате semver (https://semver.org/) |
То же самое в Groovy (Kotlin DSL):
implementation("org.apache.commons:commons-csv:1.14.1")Чтобы загрузить собственную библиотеку на Maven Central, нужно доказать владение доменом (например, прописав «магическое» значение в TXT-поле в DNS)
Благодаря давней и надёжной инфраструктуре защиты прав на доменные имена, мы гарантированы, что никто не опубликует библиотеку от имени Microsoft, Apple или Oracle.
Нет смысла «захватывать» красивые имена для библиотек или заниматься typosquatting-ом: у каждого своё пространство имён
Контраст с npm и PyPi: исчерпание «красивых» имён, typosquatting, проблемы с безопасностью. Зато — просто и изящно, в отличие от Java.
Проверьте mvn --version (по состоянию на осень 2026, Maven 3.9.x и Java 25.x)
Запустите
mvn archetype:generate \
-DarchetypeGroupId=org.atp-fivt \
-DarchetypeArtifactId=homework-quickstart \
-DarchetypeVersion=3.0Понадобится некоторое время, чтобы скачать и закешировать нужные библиотеки
Заполните groupId, (например, edu.phystech), artifactId ( например, homework1)
Примите значения по умолчанию для version и package
Исследуйте содержимое файла pom.xml и структуру папок. "Hello world" пример находится в App.java.
Запустите сборку с помощью mvn verify.
<build><plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<configuration> (1)
<archive><manifest>
<mainClass>edu.phystech.App</mainClass>
</manifest></archive>
</configuration>
</plugin>| 1 | Plugin parameters |
java -jar target\helloworld-1.0-SNAPSHOT.jar
Hello World!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Красным жирным — слова из языка C. | |||
|
|
|
var var = 42;(Java 9)
open module requires transitive exports
opens to uses provides with
(Java 10)
var
(Java 14)
yield record
(Java 15)
sealed non-sealed permits
(Java 21)
when/**
* This is the first sample program in Core Java Chapter 3
* @version 1.01 1997-03-22
* @author Gary Cornell
*/
public class FirstSample
{
public static void main(String[] args)
{
/*multiline
comment*/
System
.out //single-line comment
.println("We will not use 'Hello, World!'");
}
}Value
Примитивные
byte, short, int, long
char
float, double,
boolean
Reference
Массивы
Объекты
null, будь он неладен
Type | Storage | Range |
| 1 byte | –128 to 127 |
| 2 bytes | –32,768 to 32,767 |
| 4 bytes | –2,147,483,648 to 2,147,483, 647 |
| 8 bytes | –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
Long 100L
Underscores 1_000_000
Hexadecimal 0xCAFEBABE
Binary 0b0101
Octal 010
Type | Storage | Range |
| 4 bytes | Approximately ±3.40282347E+38F (6–7 significant decimal digits) |
| 8 bytes | Approximately ±1.79769313486231570E+308 (15 significant decimal digits) |
2.998e8
1.0 (1.)
3.14F
0x1.0p-3 (0.125, 2 в минус третьей степени)
Double.POSITIVE_INFINITY
Double.NEGATIVE_INFINITY
Double.NaN
System.out.println(2.0 - 1.1) выводит 0.8999999999999999
НИКОГДА НЕ СЧИТАЙТЕ ДЕНЬГИ DOUBLE-ОМ!
System.out.println(2.0 / 0.0) выводит 'Infinity` (но 2 / 0 — divizion by zero)
System.out.println(0.0 / 0.0) выводит 'NaN`
Сравнение с бесконечностью и NaN не работает, надо проверять с помощью Double.isNaN, Double.isInfinite.
strictfp

double x = 9.997F; //float в double неявно
int nx = (int) x; //9
nx = (int) Math.round(x); //10char16 bit
code unit in the UTF-16 encoding
Не всегда целый символ (хотя почти всегда)!
Осторожней с Unicode, используйте String
char'ы'
'\u03C0' (греческая π)
'\'' (escaped single quote)
Ловушка Unicode Escape: // Look inside c:\users
String s = "Hello, world!";
//Before Java 13
String txt =
"Some\n" +
" Nested\n" +
" Text\n" +
" Is\n" +
"Here\n";Some
Nested
Text
Is
Here String txt = """
Some
Nested
Text
Is
Here
""";//Максимальное число пробелов впереди убрано:
Some
Nested
Text
Is
HereEscape sequence | Name | Unicode Value |
| Backspace | \u0008 |
| Tab | \u0009 |
| Linefeed | \u000a |
| Carriage return | \u000d |
| Double quote | \u0022 |
| Single quote | \u0027 |
| Backslash | \u005c |
| intentional whitespace (Java 13+) | |
| line continuation (Java 13+) |
booleantrue и false
В отличие от C и многих других языков, целые числа не сводятся автоматически к boolean
Избегаем ошибок вида if (x = 0) {…
// декларация
double salary;
int vacationDays;
long earthPopulation;
boolean done;
// не очень приветствуется
int i, j;
// технически можно, но . . .
int суммаНДФЛ;int vacationDays;
System.out.println(vacationDays); //COMPILATION ERROR
// variable not initializedВозможные способы инициализации:
int vacationDays;
vacationDays = 12;int vacationDays = 12;final (константы)final используется в двух смыслах:
запрещает изменять значение
запрещает переопределять методы/классы
final int a;
...
a = 42; // инициализация
...
a = 43; // compilation error:
// variable a might already have been initializedМесто определения: класс, метод, блок
Нет ничего за пределами класса («глобальных» переменных)!
int n;
. . .
{
int k;
int n; // Error--can't redefine n in inner block
. . .
} // k is only defined up to herevar i = 1; // i is of int type//BEFORE JAVA 10
URL codefx = new URL("http://codefx.org");
URLConnection connection = codefx.openConnection();
Reader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream()));//AFTER JAVA 10
var codefx = new URL("http://codefx.org");
var connection = codefx.openConnection();
var reader = new BufferedReader(
new InputStreamReader(connection.getInputStream()));Арифметические: +, -, *, /, %
Деление работает как целочисленное, если оба аргумента целочисленные
Унарные + и -.
|
| |
|
| |
|
| |
|
| Дополнительный код (two’s complement), инверсия и добавление 1. |
|
| |
|
| старший (знаковый) бит сохраняется |
|
| старший (знаковый) бит заполняется нулём |
5 >> 32 == ?
5 >> 32 == 5
для int используются только 5 младших бит второго операнда (0..31),
для long используются только 6 младших бит второго операнда (0..63)
&, |, ^, ~
<, <=
>, >=
==, !=
instanceof
Без короткого замыкания: &, |, ^, ! (вместо тильды — восклицательный знак!)
С коротким замыканием &&, ||.
x != 0 && 1 / x > x + y // no division by 0int x;
System.out.println(x = 42); //печатает 42Пример использования:
while ((n = readValue()) != null)
... //делаем что-то с na++, ++a
a--, --a
+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, >>>=
ВНИМАНИЕ: может показаться, что эти операции атомарны. Но это не так.
x < y ? x : yOperators | Associativity |
| Left to right |
| Right to left |
| Left to right |
| Left to right |
| Left to right |
| Left to right |
| Left to right |
Operators | Associativity |
| Left to right |
| Left to right |
| Left to right |
| Left to right |
| Left to right |
//У конъюнкции выше приоритет, чем у дизъюнкции, поэтому
a || b && c
// есть по сути
a || (b && c)Operators | Associativity |
| Right to left |
| Right to left |
//Since += associates right to left, the expression
a += b += c
//means
a += (b += c)
//That is, the value of b += c
// (which is the value of b after the addition)
//is added to a.А его нет!
Можно несколько statement-ов перечислить через запятую в блоке for(…) (дань уважения языку C):
double r;
for (int i = 0; i < 10; i++, r = Math.random()) {
}Из любого типа можно построить массив данного типа.
Длина массива может быть определена в runtime, но после создания не может быть изменена.
Массив аллоцируется в куче и передаётся по ссылке.
Массивы проверяют тип данных (ArrayStoreException) и границы (ArrayIndexOutOfBoundsException) в run-time.
Правда жизни: скорее всего, вы не будете использовать массивы в современном коде.
Два варианта:
int[] a
int a[] — совместимая с языком C декларация, но не делайте так в Java!
Инициализация:
int[] a = new int[100];
int[] a = {1, 3, 5};
анонимный массив: foo(new int[] {2, 4, 6});
| ![]() |
| ![]() |
LocalDate[100_000] before Valhalla: (24 LocalDate object + 4 ref) * 100 000 = 2 800 000 bytes, 100 000 allocations.
Flattened LocalDate[100_000]: (8 flattened LocalDate) *100 000 = 800 000 bytes, zero allocations.
int[] luckyNumbers = smallPrimes;
luckyNumbers[5] = 12; // теперь smallPrimes[5] тоже 12
luckyNumbers = Arrays.copyOf(luckyNumbers, 2 * luckyNumbers.length);
//теперь luckyNumbers это отдельный массив
//и он стал в два раза длиннее String[] a = new String[1];
//компилируется. ведь строка это объект,
//и потому почему б не считать массив строк массивом объектов?
Object[] b = a;
//runtime ArrayStoreException
b[0] = 5;(Всё это страшно не совместимо с дженериками и коллекциями, которые пытаются ловить ошибки типов во время компиляции, но об этом речь впереди.)
На самом деле их нет, но есть массивы массивов
| ![]() |
| ![]() |
if | ![]() |
if + block | ![]() |
if + block + else | ![]() |
else группируется с ближайшим if | ![]() |
else if | ![]() |
switchПолностью совместим с классическим switch в языке C, но имеет мощные расширения. Пожалуй, наиболее сильно переработанная синтаксическая конструкция из унаследованных из C.
| ![]() |
switch-case особенности:Используя "C-style" switch, не забываем break-и (утилиты типа Checkstyle напоминают), иначе выполняем всё до конца switch, как в C!
Обычный switch бывает: по целому, по char-у, по String-у (Java 7+), по enum-у.
Бывает также switch c pattern matching (Java 21+), о котором мы расскажем в других лекциях.
Expression | Statement |
| |
Expression | Statement (Good Old C-style Switch) |
| |
while: то же, что и в C | ![]() |
do while: цикл с постусловием | ![]() |
Правда жизни: do-while бывает нужен очень, ОЧЕНЬ редко.
forСнова всё то же, что и в C (по сути, сокращение цикла while):
for (int i = 1; i <= 10; i++)
System.out.println(i);И даже, хотя оператора «запятая» нет, можно так (но не нужно):
for (int i = 1; i <= 10; i++, j++)
System.out.println(i);for (int i = 1; i <= 10; i++)
{
. . .
}
// i no longer defined hereint i;
for (i = 1; i <= 10; i++)
{
. . .
}
// i is still defined herebreak и continueПрерывание цикла целиком:
while (years <= 100) {
balance += payment;
double interest = balance * interestRate / 100;
balance += interest;
if (balance >= goal) break;
years++;
}Переход к следующему циклу:
Scanner in = new Scanner(System.in);
while (sum < goal) {
System.out.print("Enter a number: ");
n = in.nextInt();
if (n < 0) continue;
sum += n; // not executed if n < 0
}goto, но есть метки для break и continue!Scanner in = new Scanner(System.in); int n;
read_data: while (. . .) { // <<<label is here!
. . .
for (. . .) {
System.out.print("Enter a number >= 0: ");
n = in.nextInt();
if (n < 0)
break read_data;
// break out of read_data loop
. . .
}
}
if (n < 0) {
// deal with bad situation
} else {
// carry out normal processing
}