Тест всегда должен предлагать выбор только правильных вариантов, а вопрос может быть переформулирован как «Это не может быть».
Короче, вот так вот не надо:
Эти небесные тела являются планетами
Выберите неверные ответы
А надо так:
Эти небесные тела планетами не являются
Задача 1
public class Quiz_1 {
public static void print() {
System.out.print("A");
}
public static void main(String[] args) {
((Quiz_1) null).print();
System.out.print("B");
}
}
Варианты ответов:
- AB
- B
- NullPointerException
- Compilation error
Задача 2
public class Quiz_2 {
public void func(Integer i) {
System.out.println("integer"); }
public void func(Double i) {
System.out.println("double"); }
public void func(Object i) {
System.out.println("object"); }
public static void main(String[] args) {
List> nums = Arrays.asList(1/2);
new Quiz_2().func(nums.get(0));
}
}
Варианты ответов:
- integer
- double
- object
- Runtime exception
- Compilation error
Правильный ответ
3. object
… из-за того, что список List<?> nums
типизирован <?>. Такой вайлдкард вернёт Object в любой ситуации, а компилятор заранее скомпилирует представленный код с вызовом правильной функции, а именно public void func(Object i) {
.
Задача 3
public class Quiz_3 {
public static void main(String[] args) {
System.out.println(
true?false:true == true?false:true
);
}
}
Варианты ответов:
- true
- false
- Compilation error
Задача 4
public class Quiz_4 {
public static void main(String[] args) {
int n = 1;
int result = Optional.of(n++)
.map(i -> i + n)
.orElse(-1);
System.out.println(result);
}
}
Варианты ответов:
- 2
- 3
- 4
- -1
- Runtime exception
- Compilaction error
Правильный ответ
6. Compilation error
Переменная n
должна быть финальной, чтобы использоваться в лямбда-выражении i -> i + n
. С другой стороны, n
не может быть финальной из-за унарного оператора ++ в выражении Optional.of(n++)
.
Задача 5
public class Quiz_5 {
public static void main(String[] args) {
int n = Integer.MAX_VALUE;
n++;
System.out.println(n + n);
}
}
Варианты ответов:
- -2
- 0
- 2
- 4294967296 (2^32)
- Runtime exception
- Compilation error
Правильный ответ
2. 0
Начнём с того, что Integer.MAX_VALUE + 1 = Integer.MIN_VALUE
. В бинарном представлении значение Integer.MAX_VALUE (01111111111111111111111111111111) при добавлении к нему единицы получится Integer.MIN_VALUE (10000000000000000000000000000000). При сложении 2-х этих чисел сумма старших битов даст 102, что приведёт к переполнению в памяти. Поскольку 1 будет некуда записать в 32-х битном представлении, то останутся только нули.
Задача 1
public class Quiz_1 {
public static void main(String[] args) {
String s = null;
System.out.println(s instanceof String);
}
}
Варианты ответов:
- true
- false
- NullPointerException
- Compilaction error
Правильный ответ
2. false
Согласно пункту документации 15.20.2. Type Comparison Operator instanceof:
At run time, the result of the instanceof operator is true if the value of the RelationalExpression is not null and the reference could be cast (§15.16) to the ReferenceType without raising a ClassCastException.
Задача 2
public class Quiz_2 {
public static void main(String[] args) {
String[] strings = {"1", "1"};
Object[] objects = strings;
objects[0] = 0;
System.out.println(
Arrays.toString(objects)
);
}
}
Варианты ответов:
- [0, 2]
- [1, 2]
- Runtime exception
- Compilation error
Задача 3
public class Quiz_3 {
public static void main(String[] args) {
String str = "true";
if ("t" + "r" + "u" + "e" == "true")
System.out.print("1");
if (str + "" == "true")
System.out.print("2");
if (str.replace('T', 't') == "true")
System.out.print("3");
}
}
Варианты ответов:
- 123
- 12
- 23
- 13
- 1
- 2
- 3
Правильный ответ
4. 13
- Выражение
"t" + "r" + "u" + "e"
является строковым литералом и согласно спецификации 3.10.5. String Literals:
A long string literal can always be broken up into shorter pieces and written as a (possibly parenthesized) expression using the string concatenation operator +
[...]
Moreover, a string literal always refers to the same instance of class String.
Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals.
Strings computed by concatenation at run-time are newly created and therefore distinct.
Более того, компилятор самостоятельно вычислить выражение и в байт-код запишет следующее:
L0
LINENUMBER 15 L0
LDC "true"
ASTORE 1
L1
LINENUMBER 17 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "1"
INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/String;)V
L0 соответствует сохарнению значения «true» в переменную, а L1 соответствует выводу «1» через System.out, любые проверки отсутствуют.
- Компилятор вместо оператора конкатенации «+» в байт-коде использует java.lang.StringBuilder:
L2
LINENUMBER 18 L2
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder. ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC ""
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
LDC "true"
IF_ACMPNE L3
Метод StringBuilder.toString()
возвращает новый экземпляр типа String с новой ссылкой:
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
Именно поэтому сравнение через ==
вернёт значение false.
- В соответствии с javadoc метода
replace()
:
If the character {@code oldChar} does not occur in the character sequence represented by this {@code String} object, then a reference to this {@code String} object is returned.
Поскольку 'T'
отсутствует в исходной строке, то вернётся исходный объект.
Задача 4
public class Quiz_4 {
public static void main(String[] args) {
Stream stream =
Stream.of("A", "B");
System.out.print(1);
stream.peek(System.out::print);
System.out.print(2);
stream.forEach(System.out::print);
}
}
Варианты ответов:
- 1AB2AB
- 1A2A1B2B
- 12AB
- 12ABAB
- Runtime exception
- Compilation error
Правильный ответ
5. Runtime exception
А конкретно:
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
at java.util.stream.AbstractPipeline.sourceStageSpliterator(AbstractPipeline.java:279)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at me.markoutte.sandbox.conferences.jpoint2018.luxoft.day1.Quiz_4.main(Quiz_4.java:21)
Происходит это всё из-за того, что peek является промежуточной операцией, возвращающей новый стрим, который в данном примере отсутствует, а вызов forEach обнаруживает проблему чтения из того же стрима, что читает peek.
Задача 5
public class Quiz_5 {
public static void main(String[] args) {
HashSet set = new HashSet<>();
for (short i = 0; i < 100; i++) {
set.add(i);
set.remove(i - 1);
}
System.out.println(set.size());
}
}
Варианты ответов:
- 0
- 1
- 100
- Runtime exception
- Compilation error
Правильный ответ
3. 100
Ни одно из значений не будет удалено из сета, поскольку для операции (i - 1) будет автоматически выполнено сначала расширения типа до integer, а потом боксинг в тип Integer. Поскольку в сете хранится тип Short, а не Integer, то ни одна из операций по удалению не сможет найти нужных значений и величина массива будет равна количеству операции по добавлению. В данном случае таковых 100.
Вы и так это знали:
Тип double не очень точный тип данных
Решите, например, сегодняшнее задание на codewars:
Your task is to construct a building which will be a pile of n cubes. The cube at the bottom will have a volume of n^3, the cube above will have volume of (n-1)^3 and so on until the top which will have a volume of 1^3.
You are given the total volume m of the building. Being given m can you find the number n of cubes you will have to build?
The parameter of the function findNb (find_nb, find-nb, findNb) will be an integer m and you have to return the integer n such as n^3 + (n-1)^3 + … + 1^3 = m if such a n exists or -1 if there is no such n.
Examples:
findNb(1071225) --> 45
findNb(91716553919377) --> -1
https://www.codewars.com/kata/5592e3bd57b64d00f3000047
Переведу в кратце: необходимо вычислить количество кубиков для здания заданного объёма. Объём здания считается как сумма объёмов состовляющих его кубиков. Каждый кубик, начиная с нижнего, имеет объём
, где i — порядковый номер куба (от 1 до n) снизу.
Решение в лоб с использованием циклов:
public static long findNb(long m) {
long n = 0, totalVolume = 0;
while (totalVolume < m) {
totalVolume += ++n * n * n;
}
return totalVolume == m ? n : -1;
}
Но в университете мне что-то рассказывали про ряды и их суммы, поэтому захотелось решить задачу математически. Как считать ряды я давно забыл, но ответ вы найдёте, перейдя на Wolfram Alpha и введя sum n^3, n = 1 to k в поле поиска. Узнаем, что:

Приравняем правую часть к m и решим квадратное уравнение:


Отсюда следует, что задача решается только если
будет целым. Пишем код:
public static long findNb(long m) {
double res = Math.sqrt(m);
if (res - Math.floor(res) != 0) {
return -1;
}
double d = 1 + 8 * res;
double n = (Math.sqrt(d) - 1) / 2;
return n - Math.floor(n) == 0 ? (long) n : -1;
}
Оказывается, что для некоторого числа тестовых данных, код даёт неверный ответ. Например, для значения 1646842954019151682L
. В джаве корень из этого числа даёт:
System.out.println(String.format("%.30f", Math.sqrt(1646842954019151682L)));
// output 1283293791.000000000000000000000000000000
Тогда как правильный ответ:
1283293791.00000000038962239473657673134031176401122912...
Очевидно, что ответы не совпадают. Fin!
Вывод
Более правильное (и, наверняка, быстрое) решение не всегда даёт правильные результаты. Этим не удивишь опытного разработчика, но начинающие программисты долго могут гадать о природе ошибки.
И напоследок. Следующее выражение истинно:
System.out.println(1646842954019151681L == 1646842954019151682D);
а это ложно:
System.out.println(1646842954019151681L == (long) 1646842954019151682D);