467 lines
28 KiB
TeX
467 lines
28 KiB
TeX
\documentclass[../j-spec.tex]{subfiles}
|
||
\usepackage{spreadtab}
|
||
|
||
\begin{document}
|
||
\setcounter{section}{3}
|
||
\section{Семинар: обработка исключений}
|
||
\subsection{Инструментарий}
|
||
\begin{itemize}
|
||
\item \href{https://docs.google.com/presentation/d/151h8ULUF9r2UyV7QGO4oNiGA4msrywznKeeNMttFdGg}{Презентация} для преподавателя, ведущего семинар;
|
||
\item \href{https://drive.google.com/file/d/1LWyE8aEy4-1gsognqhXIXwDcoLviVge4/view}{Фон} GeekBrains для проведения семинара в Zoom;
|
||
\item JDK любая 11 версии и выше;
|
||
\item \href{https://www.jetbrains.com/idea/download}{IntelliJ IDEA Community Edition} для практики и примеров используется IDEA.
|
||
\end{itemize}
|
||
|
||
\subsection{Цели семинара}
|
||
\begin{itemize}
|
||
\item Закрепить полученные на лекции знания об исключениях;
|
||
\item Попрактиковаться в написании собственных классов исключений;
|
||
\item Создание, выбрасывание и обработка исключений;
|
||
\item Обработка исключений в стиле «до захвата ресурса»;
|
||
\item Проброс исключений выше по стеку.
|
||
\end{itemize}
|
||
|
||
\subsection{План-содержание}
|
||
\noindent
|
||
\begin{spreadtab}{{longtable}{|p{37mm}|l|l|p{90mm}|}}
|
||
\hline
|
||
@ Что происходит & @ Время & @ Слайды & @ Описание \\
|
||
\hline
|
||
\endhead
|
||
@ Организационный момент & 5 tag(beg) & @ 1-5 & @ Преподаватель ожидает студентов, поддерживает активность и коммуникацию в чате, озвучиает цели и планы на семинар. Важно упомянуть, что выполнение домашних заданий с лекции является, фактически, подготовкой к семинару \\
|
||
\hline
|
||
@ Quiz & 5 & @ 6-18 & @ Преподаватель задаёт вопросы викторины, через 30 секунд демонстрирует слайд-подсказку и ожидает ответов (6 вопросов, по минуте на ответ) \\
|
||
\hline
|
||
@ Рассмотрение ДЗ лекции & 10 & @ 19-23 & @ Преподаватель демонстрирует свой вариант решения домашнего задания с лекции, возможно, по предварительному опросу, демонстрирует и разбирает вариант решения одного из студентов \\
|
||
\hline
|
||
@ Вопросы и ответы & 10 & @ 24 & @ Преподаватель ожидает вопросов по теме прошедшей лекции, викторины и продемонстрированной работы \\
|
||
\hline
|
||
@ Задание 1 & 30 & @ 25-35 & @ Сквозное задание, состоящее из объяснений в 6 пунктах, обязательных к исполнению. Всё задание выдаётся сразу целиком и является неделимым. \\
|
||
\hline
|
||
@ Перерыв (если нужен) & 5 & @ 36 & @ Преподаватель предлагает студентам перерыв на 5 минут (студенты голосуют) \\
|
||
\hline
|
||
@ Задание 2 & 40 & @ 37-49 & @ Сквозное задание, состоящее из объяснений в 6 пунктах, обязательных к исполнению. Всё задание выдаётся сразу целиком и является неделимым. \\
|
||
\hline
|
||
@ Домашнее задание & 5 & @ 50-51 & @ Объясните домашнее задание, подведите итоги урока \\
|
||
\hline
|
||
@ Рефлексия & 10 tag(end) & @ 52-53 & @ Преподаватель запрашивает обратную связь \\
|
||
\hline
|
||
@ Длительность & sum(cell(beg):cell(end)) & & \\
|
||
\hline
|
||
\end{spreadtab}
|
||
|
||
\subsection{Подробности}
|
||
\subsubsection{Организационный момент}
|
||
\begin{itemize}
|
||
\item \textbf{Цель этапа:} Позитивно начать урок, создать комфортную среду для обучения.
|
||
\item \textbf{Тайминг:} 3-5 минут.
|
||
\item \textbf{Действия преподавателя:}
|
||
\begin{itemize}
|
||
\item Запрашивает активность от аудитории в чате;
|
||
\item Презентует цели курса и семинара;
|
||
\item Презентует краткий план семинара и что студент научится делать.
|
||
\end{itemize}
|
||
\end{itemize}
|
||
|
||
\subsubsection{Quiz}
|
||
\begin{itemize}
|
||
\item \textbf{Цель этапа:} Вовлечение аудитории в обратную связь.
|
||
\item \textbf{Тайминг:} 5-7 минут (4 вопроса, по минуте на ответ).
|
||
\item \textbf{Действия преподавателя:}
|
||
\begin{itemize}
|
||
\item Преподаватель задаёт вопросы викторины, представленные на слайдах презентации;
|
||
\item через 30 секунд демонстрирует слайд-подсказку и ожидает ответов.
|
||
\end{itemize}
|
||
\item \textbf{Вопросы и ответы:}
|
||
\begin{enumerate}
|
||
\item Перечисление -- это: 2
|
||
\begin{enumerate}
|
||
\item массив
|
||
\item класс
|
||
\item объект
|
||
\end{enumerate}
|
||
\item Инкапсуляция с использованием внутренних классов: 2
|
||
\begin{enumerate}
|
||
\item остаётся неизменной
|
||
\item увеличивается
|
||
\item уменьшается
|
||
\end{enumerate}
|
||
\item Обработчик исключений -- это объект, работающий 1
|
||
\begin{enumerate}
|
||
\item в специальном потоке
|
||
\item в специальном ресурсе
|
||
\item в специальный момент
|
||
\end{enumerate}
|
||
\item Стектрейс - это 2
|
||
\begin{enumerate}
|
||
\item часть потока выполнения программы;
|
||
\item часть объекта исключения;
|
||
\item часть информации в окне отладчика.
|
||
\end{enumerate}
|
||
\end{enumerate}
|
||
\end{itemize}
|
||
|
||
\subsubsection{Рассмотрение ДЗ}
|
||
\begin{itemize}
|
||
\item \textbf{Цель этапа:} Пояснить не очевидные моменты в формулировке ДЗ с лекции, синхронизировать прочитанный на лекции материал к началу семинара.
|
||
\item \textbf{Тайминг:} 15-20 минут.
|
||
\item \textbf{Действия преподавателя:}
|
||
\begin{itemize}
|
||
\item Преподаватель демонстрирует свой вариант решения домашнего задания из лекции;
|
||
\item возможно, по предварительному опросу, демонстрирует и разбирает вариант решения одного из студентов.
|
||
\end{itemize}
|
||
\item \textbf{Домашнее задание из лекции:}
|
||
\begin{itemize}
|
||
\item Напишите два наследника класса \code{Exception}: ошибка преобразования строки и ошибка преобразования столбца.
|
||
|
||
\textbf{Вариант решения}
|
||
|
||
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Простые наследники}]
|
||
private static final class ColumnMismatchException extends RuntimeException {
|
||
ColumnMismatchException(String message) {
|
||
super("Columns exception: " + message);
|
||
}
|
||
}
|
||
|
||
private static final class NumberIsNotNumberException extends RuntimeException {
|
||
NumberIsNotNumberException(String message) {
|
||
super("Not a number found: " + message);
|
||
}
|
||
}
|
||
\end{lstlisting}
|
||
|
||
\item Разработайте исключения-наследники так, чтобы они информировали пользователя в формате ожидание/реальность.
|
||
|
||
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Составное сообщение}]
|
||
private static final class RowMismatchException extends RuntimeException {
|
||
RowMismatchException(int expected, int current, String value) {
|
||
super(String.format("Rows exception: expected %d rows. Received %d rows in '%s' string",
|
||
expected, current, value));
|
||
}
|
||
}
|
||
\end{lstlisting}
|
||
|
||
\item для проверки напишите программу, преобразующую квадратный массив целых чисел 5х5 в сумму чисел в этом массиве, при этом, программа должна выбросить исключение, если строк или столбцов в исходном массиве окажется не 5.
|
||
|
||
\textbf{Вариант решения представлен в приложении \ref{appendix:hw3}}
|
||
|
||
\end{itemize}
|
||
\end{itemize}
|
||
|
||
\subsubsection{Вопросы и ответы}
|
||
\begin{itemize}
|
||
\item \textbf{Ценность этапа} Задать задание для самостоятельного выполнения между занятиями.
|
||
\item \textbf{Тайминг} 5-15 минут
|
||
\item \textbf{Действия преподавателя}
|
||
\begin{itemize}
|
||
\item Преподаватель ожидает вопросов по теме прошедшей лекции, викторины и продемонстрированной работы;
|
||
\item Если преподаватель затрудняется с ответом, необходимо мягко предложить студенту ответить на его вопрос на следующем семинаре (и не забыть найти ответ на вопрос студента!);
|
||
\item Предложить и показать пути самостоятельного поиска студентом ответа на заданный вопрос;
|
||
\item Посоветовать литературу на тему заданного вопроса;
|
||
\item Дополнительно указать на то, что все сведения для выполнения домашнего задания, прохождения викторины и работы на семинаре были рассмотрены в методическом материале к этому или предыдущим урокам.
|
||
\end{itemize}
|
||
\end{itemize}
|
||
|
||
\subsubsection{Задание 1}
|
||
\begin{itemize}
|
||
\item \textbf{Ценность этапа} Написание почти полноценной механики по краткому ТЗ.
|
||
\item \textbf{Тайминг} 25-30 минут.
|
||
\item \textbf{Действия преподавателя}
|
||
\begin{itemize}
|
||
\item Выдать задание студентам;
|
||
\item Подробно объяснить, что именно требуется от студентов, избегая упоминания конкретных языковых конструкций.
|
||
\end{itemize}
|
||
\item \textbf{Задание}: Класс «Проверка логина и пароля».
|
||
\begin{enumerate}
|
||
\item Создать статический метод который принимает на вход три параметра: \code{login}, \code{password} и \code{confirmPassword}.
|
||
\item Длина \code{login} должна быть \textbf{меньше} 20 символов. Если \code{login} не соответствует этому требованию, необходимо выбросить \code{WrongLoginException}.
|
||
\item Длина \code{password} должна быть \textbf{не меньше} 20 символов. Также \code{password} и \code{confirmPassword} должны быть равны. Если \code{password} не соответствует этим требованиям, необходимо выбросить \code{WrongPasswordException}.
|
||
\item \code{WrongPasswordException} и \code{WrongLoginException} -- пользовательские классы исключения с двумя конструкторами –- один по умолчанию, второй принимает параметры исключения (неверные данные) и возвращает пользователю в виде «ожидалось/фактически».
|
||
\item В основном классе программы необходимо по-разному обработать исключения.
|
||
\item Метод возвращает \code{true}, если значения верны или \code{false} в противном случае.
|
||
\end{enumerate}
|
||
\textbf{Вариант исполнения класса в приложении \ref{appendix:ct1}}
|
||
|
||
\textbf{Вариант маршрута решения задачи}
|
||
|
||
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Описание класса исключения логина}]
|
||
public static class WrongLoginException extends RuntimeException {
|
||
private int currentLength;
|
||
public WrongLoginException(int currentLength) {
|
||
super();
|
||
this.currentLength = currentLength;
|
||
}
|
||
|
||
@Override
|
||
public String getMessage() {
|
||
return String.format("Your login is of incorrect length, expected < 20, given %d.",
|
||
currentLength);
|
||
}
|
||
}
|
||
\end{lstlisting}
|
||
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Формирование сообщения для класса исключения пароля}]
|
||
public static class WrongPasswordException extends RuntimeException {
|
||
private int currentLength;
|
||
private boolean matchConfirm;
|
||
public WrongPasswordException(int currentLength, boolean matchConfirm) {
|
||
super();
|
||
this.currentLength = currentLength;
|
||
this.matchConfirm = matchConfirm;
|
||
}
|
||
|
||
@Override
|
||
public String getMessage() {
|
||
boolean badlen = currentLength <= 20;
|
||
return String.format("Your password is of %scorrect length%s %d. Password %smatch the confirmation.",
|
||
((badlen) ? "in" : ""),
|
||
((badlen) ? ", expected > 20, given" : ","),
|
||
currentLength,
|
||
(matchConfirm) ? "" : "doesn't ");
|
||
}
|
||
}
|
||
\end{lstlisting}
|
||
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Создание тестовой среды}]
|
||
public static void main(String[] args) {
|
||
String[][] credentials = {
|
||
{"ivan", "1i2v3a4n5i6v7a8n91011", "1i2v3a4n5i6v7a8n91011"}, //correct
|
||
{"1i2v3a4n5i6v7a8n91011", "", ""}, //wrong login length
|
||
{"ivan", "1i2v3a4n5i6v7a8n91011", "1i2v3a4n5"}, //confirm mismatch
|
||
{"ivan", "1i2v3a4n5", "1i2v3a4n5"},//wrong password length
|
||
{"ivan", "1i2v3a4n5", "1i"} //wrong password length and confirm mismatch
|
||
};
|
||
for (int i = 0; i < credentials.length; i++) {
|
||
try {
|
||
System.out.println(checkCredentials(credentials[i][0], credentials[i][1], credentials[i][2]));
|
||
} catch (WrongLoginException e) {
|
||
e.printStackTrace();
|
||
} catch (WrongPasswordException e) {
|
||
System.out.println(e.getMessage());
|
||
}
|
||
}
|
||
}
|
||
\end{lstlisting}
|
||
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Метод проверки}]
|
||
public static boolean checkCredentials(String login, String password, String confirmPassword) {
|
||
boolean conf = password.equals(confirmPassword);
|
||
int llen = login.length();
|
||
int plen = password.length();
|
||
if (llen >= 20)
|
||
throw new WrongLoginException(llen);
|
||
else if (plen < 20 || !conf)
|
||
throw new WrongPasswordException(plen, conf);
|
||
else
|
||
return true;
|
||
}
|
||
\end{lstlisting}
|
||
|
||
\end{itemize}
|
||
|
||
\subsubsection{Задание 2}
|
||
\begin{itemize}
|
||
\item \textbf{Ценность этапа} Написание наброска пет-проекта, повторение информации об ООП, работа с исключениями.
|
||
\item \textbf{Тайминг} 35-40 минут.
|
||
\item \textbf{Действия преподавателя}
|
||
\begin{itemize}
|
||
\item Выдать задание студентам;
|
||
\item Подробно объяснить, что именно требуется от студентов, избегая упоминания конкретных языковых конструкций.
|
||
\item обратить внимание на порядок обработки исключений, повторная попытка купить товар может производиться только тогда, когда остальные параметры покупки уже проверены.
|
||
\end{itemize}
|
||
\item \textbf{Задание}: Класс «Эмуляция интернет-магазина».
|
||
\begin{enumerate}
|
||
\item Написать классы покупатель (ФИО, возраст, телефон), товар (название, цена) и заказ (объект покупатель, объект товар, целочисленное количество).
|
||
\item Создать массив покупателей (инициализировать 2 элемента), массив товаров (инициализировать 5 элементов) и массив заказов (пустой на 5 элементов).
|
||
\item Создать статический метод «совершить покупку» со строковыми параметрами, соответствующими полям объекта заказа. Метод должен вернуть объект заказа.
|
||
\item Если в метод передан несуществующий покупатель -- метод должен выбросить исключение \code{CustomerException}, если передан несуществующий товар, метод должен выбросить исключение \code{ProductException}, если было передано отрицательное или слишком больше значение количества (например, 100), метод должен выбросить исключение \code{AmountException}.
|
||
\item Вызвать метод совершения покупки несколько раз таким образом, чтобы заполнить массив покупок возвращаемыми значениями. Обработать исключения следующим образом (в заданном порядке):
|
||
\begin{itemize}
|
||
\item если был передан неверный товар -- вывести в консоль сообщение об ошибке, не совершать данную покупку;
|
||
\item если было передано неверное количество -- купить товар в количестве 1;
|
||
\item если был передан неверный пользователь -- завершить работу приложения с исключением.
|
||
\end{itemize}
|
||
\item Вывести в консоль итоговое количество совершённых покупок после выполнения основного кода приложения.
|
||
\end{enumerate}
|
||
\textbf{Вариант исполнения класса в приложении \ref{appendix:ct1}}
|
||
|
||
\textbf{Вариант маршрута решения задачи}
|
||
|
||
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Создание базовых классов (идентично)}]
|
||
private static class Item {
|
||
String name;
|
||
int cost;
|
||
|
||
public Item(String name, int cost) {
|
||
this.name = name;
|
||
this.cost = cost;
|
||
}
|
||
|
||
@Override
|
||
public String toString() {
|
||
return "Item{name='" + name + "', cost=" + cost + "}";
|
||
}
|
||
}
|
||
\end{lstlisting}
|
||
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Создание пользовательских исключений}]
|
||
public static class CustomerException extends RuntimeException {
|
||
public CustomerException(String message) {
|
||
super(message);
|
||
}
|
||
}
|
||
\end{lstlisting}
|
||
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Создание массивов}]
|
||
private final static Customer[] people = {
|
||
new Customer("Ivan", 20, "+1-222-333-44-55"),
|
||
new Customer("Petr", 30, "+2-333-444-55-66"),
|
||
};
|
||
private final static Item[] items = {
|
||
new Item("Ball", 100),
|
||
new Item("Sandwich", 1000),
|
||
new Item("Table", 10000),
|
||
new Item("Car", 100000),
|
||
new Item("Rocket", 10000000)
|
||
};
|
||
private static Order[] orders = new Order[5];
|
||
\end{lstlisting}
|
||
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Описание тестовой среды}]
|
||
Object[][] info = {
|
||
{people[0], items[0], 1}, //good
|
||
{people[1], items[1], -1}, //bad amount -1
|
||
{people[0], items[2], 150}, //bad amount >100
|
||
{people[1], new Item("Flower", 10), 1}, //no item
|
||
{new Customer("Fedor", 40, "+3-444-555-66-77"), items[3], 1}, //no customer
|
||
};
|
||
int capacity = 0;
|
||
int i = 0;
|
||
while (capacity != orders.length - 1 || i != info.length) {
|
||
try {
|
||
orders[capacity] = buy((Customer) info[i][0], (Item) info[i][1], (int) info[i][2]);
|
||
capacity++;
|
||
} catch (ProductException e) {
|
||
e.printStackTrace();
|
||
} catch (AmountException e) {
|
||
orders[capacity++] = buy((Customer) info[i][0], (Item) info[i][1], 1);
|
||
} catch (CustomerException e) {
|
||
throw new RuntimeException(e);
|
||
} finally {
|
||
System.out.println("Orders made: " + capacity);
|
||
}
|
||
++i;
|
||
}
|
||
\end{lstlisting}
|
||
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Написание и \textbf{отладка} основного метода}]
|
||
private static boolean isInArray(Object[] arr, Object o) {
|
||
for (int i = 0; i < arr.length; i++)
|
||
if (arr[i].equals(o)) return true;
|
||
return false;
|
||
}
|
||
|
||
public static Order buy(Customer who, Item what, int howMuch) {
|
||
if (!isInArray(people, who))
|
||
throw new CustomerException("Unknown customer: " + who);
|
||
if (!isInArray(items, what))
|
||
throw new ProductException("Unknown item: " + what);
|
||
if (howMuch < 0 || howMuch > 100)
|
||
throw new AmountException("Incorrect amount: " + howMuch);
|
||
return new Order(who, what, howMuch);
|
||
}
|
||
\end{lstlisting}
|
||
\end{itemize}
|
||
|
||
\subsubsection{Домашнее задание}
|
||
\begin{itemize}
|
||
\item \textbf{Ценность этапа} Задать задание для самостоятельного выполнения между занятиями.
|
||
\item \textbf{Тайминг} 5-10 минут.
|
||
\item \textbf{Действия преподавателя}
|
||
\begin{itemize}
|
||
\item Пояснить студентам в каком виде выполнять и сдавать задания
|
||
\item Уточнить кто будет проверять работы (преподаватель или ревьювер)
|
||
\item Объяснить к кому обращаться за помощью и где искать подсказки
|
||
\item Объяснить где взять проект заготовки для дз
|
||
\end{itemize}
|
||
\item \textbf{Задания}
|
||
\begin{enumerate}
|
||
\item [5-25 мин] Выполнить все задания семинара, если они не были решены, без ограничений по времени;
|
||
|
||
\textbf{Все варианты решения приведены в тексте семинара выше}
|
||
\item [15 мин] 1. В класс покупателя добавить перечисление с гендерами, добавить в сотрудника свойство «пол» со значением созданного перечисления. Добавить геттеры, сеттеры.
|
||
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Свойства сотрудника}]
|
||
enum Genders{MALE, FEMALE};
|
||
|
||
// ...
|
||
Genders gender;
|
||
|
||
public Employee(String name, String midName, String surName, String phone, String position, int salary, int birth, Genders gender) {
|
||
// ...
|
||
this.gender = gender;
|
||
}
|
||
|
||
public Genders getGender() {
|
||
return gender;
|
||
}
|
||
|
||
public void setGender(Genders gender) {
|
||
this.gender = gender;
|
||
}
|
||
\end{lstlisting}
|
||
\item [20-25 мин] 2. Добавить в основную программу перечисление с праздниками (нет праздника, Новый Год, 8 марта, 23 февраля), написать метод, принимающий массив сотрудников, поздравляющий всех сотрудников с Новым Годом, женщин с 8 марта, а мужчин с 23 февраля, если сегодня соответствующий день.
|
||
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={Праздники}]
|
||
enum Parties{NONE, NEW_YEAR, MARCH_8, FEB_23}
|
||
private static final Parties today = Parties.NONE;
|
||
|
||
private static void celebrate(Employee[] emp) {
|
||
for (int i = 0; i < emp.length; i++) {
|
||
switch (today) {
|
||
case NEW_YEAR:
|
||
System.out.println(emp[i].name + ", happy New Year!");
|
||
break;
|
||
case FEB_23:
|
||
if (emp[i].gender == Employee.Genders.MALE)
|
||
System.out.println(emp[i].name + ", happy February 23rd!");
|
||
break;
|
||
case MARCH_8:
|
||
if (emp[i].gender == Employee.Genders.FEMALE)
|
||
System.out.println(emp[i].name + ", happy march 8th!");
|
||
break;
|
||
default:
|
||
System.out.println(emp[i].name + ", celebrate this morning!");
|
||
}
|
||
}
|
||
}
|
||
\end{lstlisting}
|
||
\end{enumerate}
|
||
\end{itemize}
|
||
|
||
\subsubsection{Рефлексия и завершение семинара}
|
||
\begin{itemize}
|
||
\item \textbf{Цель этапа:} Привести урок к логическому завершению, посмотреть что студентам удалось, что было сложно и над чем нужно еще поработать
|
||
\item \textbf{Тайминг:} 5-10 минут
|
||
\item \textbf{Действия преподавателя:}
|
||
\begin{itemize}
|
||
\item Запросить обратную связь от студентов.
|
||
\item Подчеркните то, чему студенты научились на занятии.
|
||
\item Дайте рекомендации по решению заданий, если в этом есть необходимость
|
||
\item Дайте краткую обратную связь студентам.
|
||
\item Поделитесь ощущением от семинара.
|
||
\item Поблагодарите за проделанную работу.
|
||
\end{itemize}
|
||
\end{itemize}
|
||
|
||
\newpage
|
||
\appendix
|
||
\section*{Приложения}
|
||
\addcontentsline{toc}{section}{Приложения}
|
||
\renewcommand{\thesubsection}{\Asbuk{subsection}}
|
||
|
||
\subsection{Домашнее задание 3}
|
||
\label{appendix:hw3}
|
||
\lstinputlisting[language=Java,style=JCodeStyle,caption={Основная программа}]{src/s04-hw3-exceptional.java}
|
||
|
||
\subsection{Практическое задание 1}
|
||
\label{appendix:ct1}
|
||
\lstinputlisting[language=Java,style=JCodeStyle,caption={Логин}]{src/s04-ct1-sign.java}
|
||
|
||
\subsection{Практическое задание 2}
|
||
\label{appendix:ct2}
|
||
\lstinputlisting[language=Java,style=JCodeStyle,caption={Магазин}]{src/s04-ct2-shop.java}
|
||
|
||
\end{document}
|