74-78,162-170,268-275,312-317,400-409,513-523,634-644,683-689,759-769,808-816
99-115,188-212,295-316,341-356,427-453,540-569,660-689,712-729,787-816,837-858
.
Notes taken after exam:
security-constraint/user-data-constraint/transport-guarantee
in web.xml
for JAX-WS and as ejb/webservice-endpoint/transport-guarantee
in sun-ejb-jar.xml
for EJB-based services):CONFIDENTIAL
when the application requires that data be transmitted so as to prevent other entities from observing the contents of the transmission.INTEGRAL
when the application requires that the data be sent between client and server in such a way that it cannot be changed in transit.NONE
indicates that the container must accept the constrained requests on any connection, including an unprotected one.@XmlAttachmentRef
to mark JAXB bean property, @WebMethod
return value or parameter to specify binary content that should be serialized as MIME attachment (wsi:swaRef
) see Using SwaRef with JAX-WS endpoints.@WebService
-annotated bean that has class name Hello
is published as /HelloService
<Signature>
element must be excluded from the calculations of the data digest and signature value). Check for other more complicated examples with partial document signing in article XML Digital Signature Service. <CanonicalizationMethod …/>
defines the algorithm by which a particular physical representation of XML document can be consistently reduced to its canonical (simplest but still logically equivalent) form.
new byte[]
may be omitted for variable initializer, but not for function call and for
-loop.IllegalMonitorStateException
is thrown and when InterruptedException
should be caught.
Feature Access Mode | Feature may be statically imported into same-package source file | Feature may be statically imported into different-package source file |
---|---|---|
Public | Yes | Yes |
Protected | Yes | No |
Default | Yes | No |
Private | No | No |
Feature \ Modifier | public | protected | private | final | abstract | static | transient | volatile | synchronized | native | strictfp |
---|---|---|---|---|---|---|---|---|---|---|---|
top-level class | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
inner class | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
method class | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
interface | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
class variable | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
constructor | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
method | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
method variable | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
method parameter | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
code block | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
null
a keyword? null
is a keyword, but:
From JLS §4.1:
null
is merely a special literal that can be of any reference type.
From JavaRanch SCJP FAQ and Java Language Keywords:
true
,false
, andnull
might seem like keywords, but they are actually literals
See also What is null in Java?
final
or abstract
class + private constructor
strictfp
, transient
, volatile
? strictfp
is a keyword and can be used to modify a class or a method, but never a variable. Marking a class as strictfp
means that any method code in the class will conform to the IEEE 754 standard rules for floating points. Without that modifier, floating points used in the methods might behave in a platform-dependent way (page 15). With strictfp
, you can predict how your floating points will behave regardless of the underlying platform the JVM is running on. The downside is that if the underlying platform is capable of supporting greater precision, a strictfp
method won't be able to take advantage of it (page 46). volatile
modifier tells the JVM that a thread accessing the variable must always reconcile its own private copy of the variable with the master copy in memory (page 59). Volatile reads and writes are to go directly to main memory, prohibiting caching values in registers and bypassing processor-specific caches. See What is the volatile keyword? How and why would you use it? for more information.
Character.isJavaIdentifierStart(char)
and Character.isJavaIdentifierPart(char)
(page 5, 6)
protected
modifier can be applied?
abstract final
is an invalid combination? What are other invalid combinations? abstract native
, abstract static
, abstract strictfp
, native strictfp
(page 45)
interface Searchable { Searchable getSearchbale(); }
public class Sample { public Sample() { Sample s = new Sample(); // Circular execution or compile time error? } }
public class Mod { public static void main(String argv[]) { } public static native void amethod(); }
public class A { public A() { this("dummy"); // Compile-time error: recursive constructor invocation } public A(int i) { this(99); // Compile-time error: recursive constructor invocation } public A(String s) { this(); // Compile-time error: recursive constructor invocation } public static final void main(String[]) { A o1 = new A(); A o2 = new A(5); } }
public final class
or interface
?
1: public enum ImageFormat { 2: TIFF, JPEG; 3: 4: private static final void main(String[] args) { 5: } 6: }
main
method in enum
and even mark it private
(but in this case JVM won't be able to run it, see Is it allowed to declare the main method private?).
char
?
At compile time the error is generated if below is not satisfied:
java.lang.Object
can be casted to any class or interface.A
is casted to class B
, then A
should be in class hierarchy of B
.A
is final, then downcasting is not possible.B
is interface, then casting to B
is allowed.
Coupling is an object's reliance on knowledge of the internals of another entity's implementation. When object A
is tightly coupled to object B
, a programmer who wants to use or modify A
is required to have an inappropriately extensive expertise in how to use B
.
Cohesion is the degree to which a class or method resists being broken down into smaller pieces. Cohesion is desirable and is easy to recognize in its absence. Methods as well as classes can have or lack cohesion. A low-cohesion method can often be spotted by the presence of “and” in its name. For example, if you're reading the source code for a Java-based guitar-playing robot, you might come across a method named tuneDStringAndPlayDMinorScale()
. Obviously this method performs two different tasks; the only reason they are together is that playing a scale on a string is often done right after tuning that string. But often isn't always. If you separate the code into tuneDString()
and playDMinorScale()
, then people have the option of playing a different scale, or not playing a scale at all, after they tune the string.
Home
has methods chopWood()
and carryWater()
. It also has a method called chopWoodAndCarryWater()
, which just calls the other two methods. Which statements are true? chopWoodAndCarryWater()
is an example of appropriate cohesion.chopWoodAndCarryWater()
is an example of inappropriate cohesion.chopWoodAndCarryWater()
is an example of appropriate coupling.chopWoodAndCarryWater()
is an example of inappropriate coupling.
1: public abstract class A<T> 2: { 3: abstract T a(int i) {} 4: public native b(String s); 5: static abstract void c(); 6: static protected char d() {} 7: T protected e() { return null; } 8: static T x() {} 9: public void y() {} 10: } 11: 12: class B extends A<Object> 13: { 14: Object a(int i) { return i; } 15: private char d() {} 16: private void y() {} 17: }
1: public abstract class A<T> 2: { 3: abstract T a(int i) {} // abstract method has a body 4: public native b(String s); // method with no return type 5: static abstract void c(); // "static abstract" is not valid combination of modifiers 6: static protected char d() {} // no "return" statement 7: T protected e() { return null; } // return type should go after method modifiers 8: static T x() {} // "T" can't be referenced in static contents 9: public void y() {} // OK 10: } 11: 12: class B extends A<Object> 13: { 14: Object a(int i) { return i; } // OK, mind autoboxing 15: private char d() { return 0; } // this instance method cannot override the parent static method 16: private void y() {} // the visibility of A.y() cannot be reduced 17: }
ClassCastException
at runtime):
String s = "xyz"; Integer i = (Integer) (Object) s;
1: interface Writeable { 2: long write(int i); 3: } 4: 5: class Basic { 6: protected long write(int n) { 7: System.out.println("A: " + n); 8: return n; 9: } 10: } 11: 12: abstract class AbstractWriteable extends Basic implements Writeable { 13: public long write(String s) { 14: System.out.println("B: " + s); 15: return s.length(); 16: } 17: } 18: 19: class WriteableImpl extends AbstractWriteable { 20: public int write(int m) { 21: System.out.println("C: " + m); 22: return Character.forDigit(m, 10); // returns char 23: } 24: 25: public static void main(String[] args) { 26: WriteableImpl impl = new WriteableImpl(); 27: impl.write(5); 28: 29: AbstractWriteable a = impl; 30: a.write(4); 31: a.write("4"); 32: 33: Basic b = a; 34: b.write(3); 35: b.write("3"); 36: 37: Writeable w = b; 38: w.write('2'); 39: } 40: }
AbstractWriteable
goes not implement Writeable
interface.AbstractWriteable
tries to reduce the visibility of write(int i)
method.WriteableImpl
goes not implement Writeable
interface correctly.public
.long
.((AbstractWriteable) b).write("3");
Writeable w = (Writeable) b;
After all above is fixed, the output is:
C: 5 C: 4 B: 4 C: 3 B: 3 C: 50
1: class Animal { 2: public Animal() { 3: callMe(); 4: } 5: 6: public void callMe() { 7: } 8: } 9: 10: class Monkey extends Animal { 11: int a = 5; 12: 13: public Monkey() { 14: // callMe(); // we want to do it, but it's not allowed 15: super(); 16: } 17: 18: public void callMe() { 19: System.out.println("I am called before super class initialization has completed"); 20: System.out.println("a=" + a); 21: } 22: }
Monkey
class initialization has not been executed, the method callMe()
will print 0
to the output (page 142).
java.net.URL
s, java.lang.File
s.
ClassLoader
instance holds the list of all classes it has loaded and every Class
instance has a reference to the ClassLoader
it was loaded with. That means one need to release all instances of all classes loaded by a ClassLoader
, as ClassLoader
can be garbage collected only together with all classes it has loaded. That is possible only with custom ClassLoader
implementation like in Application Server (see Unloading classes in java). That also means that objects referred by static variables cannot be garbage collected. See also JLS §12.7:
A class or interface may be unloaded if and only if its defining class loader may be reclaimed by the garbage collector as discussed in §12.6. Classes and interfaces loaded by the bootstrap loader may not be unloaded.
Very interesting project is jRebel that reloads java classes dynamically and allows even swifter development cycles by negating the need to ever redeploy.
ClassNotFoundException
is thrown when the code is trying to load a class in runtime, e.g. passing its name to Class.forName()
.
NoClassDefFoundError
is thrown when the JVM is asked to load a class indirectly (e.g. as imported class), but corresponding .class
file was not found.
ExceptionInInitializerError
is thrown if there was an exception in static initialization block.
The answer which is given in What's the difference between a ClassNotFoundException and NoClassDefFoundError? is incorrect.
For unary arithmetic operators (+a
, -a
, ++a
, –a
, a++
, a–
) two rules apply, depending on the type of the single operand:
byte
, a short
, or a char
, it is converted to an int
(unless the operator is ++
or --
, in which case no conversion happens).For binary arithmetic operators there are four rules, depending on the types of the two operands:
double
, the other operand is converted to a double
.float
, the other operand is converted to a float
.long
, the other operand is converted to a long
.int
.With these rules in mind for the following code
1: short s = 9; 2: int i = 10; 3: float f = 11.1f; 4: double d = 12.2; 5: if (-s * i >= f / d) { 6: ... 7: }
what really happens in line 5 is:
short s
is promoted to an int
and then negated.int
) is multiplied by the int i
. Because both operands are of the same type, and that type is not narrower than an int
, no conversion is necessary. The result of the multiplication is an int
.float f
is divided by double d
, f
is widened to a double
. The division generates a double-precision result.int
) is to be compared to the result of step 3 (a double
). The int
is converted to a double
, and the two operands are compared. The result of a comparison is always of type boolean
.
This promotion has an important consequence for the unsigned right-shift operator when applied to values that are narrower than int. For example the expression -64 >>> 4
(the unsigned right shift; -64 = 11000000
) results -4
(11111100
) instead of expected 12
(00001100
) as it is first promoted to int
and then shift takes place.
Widening is preferred over boxing and var-args are always considered last.
For the call of the method doit((byte) 5)
the following method signatures will match in the following order:
doit(byte param)
doit(short param)
doit(int param)
doit(long param)
doit(float param)
doit(double param)
(widening is checked first)doit(Byte param)
(autoboxing)doit(Object param)
(autoboxing + widening)doit(byte… param)
or doit(Byte… param)
or doit(Object… param)
(varargs are always considered last; if two of these three are defined then there is an ambiguity)
For the call of the method doit(new byte[] {1, 2})
the following method signatures will match in the following order:
doit(byte[] param)
or doit(byte… param)
(most specific methods; if both are defined then compile-time exception is raised as they have the same signature)doit(Object param)
(less specific, but arrays are objects)doit(byte[]… param)
doit(Object… param)
doit(Object[]… param)
new Byte[] {1, 2}
)
As one can see the method doit(Object param)
acts as catch-all for everything.
Examine the following:
byte b = 0; // OK, implicit cast int i = new Integer(200); // OK, unboxing b = b + 5; // compilation error: cannot convert from int to byte b += 5; // OK: implicit cast b *= i; // OK: implicit cast, although looks like the result of multiplication is "int"
0xA4
in octal?
byte b = 10b; // Compilation error: "b" datatype suffix is incorrect byte b1 = 20; // OK, casting is not necessary char c = 19c; // Compilation error: "c" datatype suffix is incorrect; char c = 19 is fine (does not need casting) char c1 = 0x1234; // OK char c2 = \u1234; // Compilation error: the value should be enclosed into single quotes '\u1234'. double d = 1.2d; // OK double f = 3.2f; // OK, automatic widening from float to double int i = 019; // Compilation error: "019" is out-of-range octal number Short s = 1; // OK, narrowing primitive from int to short Long l = 10; // Compilation error (which is not logical) as widening from "int" to "long" does not happen, see [1]. Correct is "Long l = 10L". Object i = 2; // OK, auto-boxing to Integer i = i + '2'; // OK c = c + i; // Compilation error: right-side expression has "int" type and should be explicitly casted to "char" c += 100L; // OK
||
requires both operands to have boolean
type. If that line is removed, the output is:
12 14
byte x = 127; x += 2; System.out.println("x: " + x);
x: -127
strictfp
modifier is applied for main
method? 1: public static void main(String[] args) { 2: System.out.println(Integer.MAX_VALUE - 255 == (int) (Integer.MAX_VALUE - 255f)); 3: System.out.println(Integer.MAX_VALUE - 5 == (int) (Integer.MAX_VALUE - 5f)); 4: 5: doIntToFloatConversion(Integer.MAX_VALUE - 0xFF); // equals to 2^31 - 256 6: doIntToFloatConversion(Integer.MAX_VALUE - 5); // equals to 2^31 - 6 7: 8: System.out.println("b: " + String.format("%.2f", Float.valueOf(33554432e10f))); // can you write this number? 9: } 10: 11: static void doIntToFloatConversion(int i) { 12: float f = i; 13: 14: System.out.println("i: " + i + " (0x" + Integer.toString(i, 16) + ")"); 15: System.out.println("f: " + String.format("%.2f", Float.valueOf(f))); 16: System.out.println("i: " + (int) f + " (0x" + Integer.toString((int) f, 16) + ")"); 17: System.out.println("l: " + (long) f + " (0x" + Long.toString((long) f, 16) + ")"); 18: }
1: true 2: false 3: 4: i: 2147483392 (0x7fffff00) 5: f: 2147483392.00 6: i: 2147483392 (0x7fffff00) 7: l: 2147483392 (0x7fffff00) 8: 9: i: 2147483642 (0x7ffffffa) 10: f: 2147483648.00 11: i: 2147483647 (0x7fffffff) 12: l: 2147483648 (0x80000000) 13: 14: b: 335544320000000000.00
result
? byte
, short
, int
, long
, float
, double
short
, int
, long
, float
, double
int
, long
, float
, double
byte b = 11; short s = 13; result = b * ++s;
int
, long
, float
, double
float tmp = (float) num1 * num2; int result = (int) tmp; if (result != tmp) { // ops, overflow throw new OverflowException(); }
tmp
type with long
(long tmp = (long) num1 * num2;
) then it will. However casting from float
is more intelligent: it will assign Integer.MAX_VALUE
to result
if the value does not fit the range. So the correct check with regards to above is if (result == Integer.MAX_VALUE) // ops, overflow
.
int[] a = new int[3]; long[] b = new long[4]; long[] c = new long[10]; b[0] = a[0]; // OK b = a; // Type mismatch: cannot convert from int[] to long[] b = c; // OK, size does not matter
int[] a = new int[3]; a[1L] = 4; // Compilation error: index should be "int" value a[2.0] = 2; // Compilation error: index should be "int" value
int[][] a = new int[][]; int[][] b = new int[3][2]; int[][] c = new int[3][]; int[][] d = new int[][3]; int e[] = [10, 11, 12, 13]; Byte[] a = new Byte[] {100, 200, 300};
int[][] a = new int[][]; // error: does not define the dimensions int[][] b = new int[3][2]; // OK, array is ready for use int[][] c = new int[3][]; // OK, all 1st level elements are nulls int[][] d = new int[][3]; // error: should define higher-level dimension prior to deeper dimension int e[] = [10, 11, 12, 13]; // error: should enclose the values in curly brackets {10, 11, ...}. Byte[] a = new Byte[] {100, 200, 300}; // error; one can in general create array like this, but the last two values exceed the byte boundary
ArrayStoreException
in runtime when brr[1]
is assigned a Boolean
value (instead of required String
).
index
. The array may be of any type (Object
or primitive). public static Object remove(Object array, int index) { int length = Array.getLength(array); Object result = Array.newInstance(array.getClass().getComponentType(), length - 1); // Copy elements to new array up to given index: System.arraycopy(array, 0, result, 0, index); if (index < length - 1) { // Copy the tail: System.arraycopy(array, index + 1, result, index, length - index - 1); } return result; }
java.lang.Integer
objects in range -128..127
. What method in this class provides the support for this? Integer.valueOf(int i);
1: Integer a = 1000, b = 1000; 2: System.out.println(a == b); 3: 4: Integer c = 100, d = 100; 5: System.out.println(c == d);
Integer
falls within a range (from -128 to 127). In line 4, no new reference of type Integer
is created for d
. Instead of creating a new object for the Integer
type reference variable d
, it is only assigned with a previously created object referenced by c
.
By the way, the higher boundary of the cache can be controlled by java.lang.Integer.IntegerCache.high
system variable.
1: import java.io.File; 2: import java.net.MalformedURLException; 3: import java.net.URL; 4: 5: public class Test { 6: 7: static final URL url; 8: 9: static { 10: try { 11: url = new URL("http://www.google.com"); // 1: Is called first, because it is static class initializer 12: } 13: catch (MalformedURLException e) {} 14: } 15: 16: { 17: final File file = new File("input.txt"); // 2: Is called first, because it is shared instance initialization block 18: count++; // count is 1 after this line is executed 19: message = "Test"; 20: } 21: 22: int count = 5; // 3: Is called first, because it is instance variable initializer 23: 24: { 25: count++; // 4: 26: } 27: 28: final String message; 29: 30: public Test() { 31: super(); // 5: Is called first, because super class needs to be initialized first 32: message = "Hello, user "; // 6: 33: } 34: 35: public static void main(String[] args) { 36: Test t = new Test(); // 7: Is called first to invoke the constructor 37: System.out.println(t.message + t.count); 38: } 39: }
1: import java.io.File; 2: import java.net.MalformedURLException; 3: import java.net.URL; 4: 5: public class Test { 6: 7: static final URL url; // Compilation error: The blank final field url may not have been initialized 8: 9: static { 10: try { 11: url = new URL("http://www.google.com"); // 1: The class is loaded by class loader and static initialization block is called 12: } 13: catch (MalformedURLException e) {} 14: } 15: 16: { 17: final File file = new File("input.txt"); // 4: The instance initialization block is called; page 236 18: count++; // Compilation problem: Cannot reference a field before it is defined 19: message = "Test"; // That is legal to initialize the instance variable before it is declared 20: } 21: 22: int count = 5; // 5: Instance variables are initialized 23: 24: { 25: count++; // 6: The instance initialization block is called 26: } 27: 28: final String message; 29: 30: public Test() { 31: super(); // 3: The super constructor is called 32: // 7: The initialization proceeds 33: message = "Hello, user "; // Compilation problem: The final field message may already have been assigned 34: } 35: 36: public static void main(String[] args) { 37: Test t = new Test(); // 2: The class instantiation is requested 38: System.out.println(t.message + t.count); // The output is: "Hello, user 6" 39: } 40: }
Look at another interesting example with singleton.
1: public class Test { 2: private static final byte MAX = getMax(); 3: 4: private static final byte getMax() { 5: return Byte.MAX_VALUE; 6: } 7: 8: public boolean hasMax(byte[] bytes) { 9: for (int i = 0; i < bytes.length; i++) { 10: switch (bytes[i]) { 11: case MAX: 12: return true; 13: } 14: } 15: 16: return false; 17: } 18: }
case expressions must be constant expressions
.
1: class Test { 2: 3: public void print(int a) { 4: System.out.println("I " + a); 5: } 6: 7: public void print(int... a) { 8: System.out.println("A " + Arrays.toString(a)); 9: } 10: 11: public void print(Object a) { 12: System.out.println("O " + a); 13: } 14: 15: public void test() { 16: print(1); 17: print(); 18: print(null); 19: print(1.2f); 20: } 21: }
I 1 A [] A null O 1.2
The code variation with explanations:
1: class Test { 2: 3: public void print(int a) { 4: System.out.println("I " + a); 5: } 6: 7: public void print(int... a) { 8: System.out.println("A " + Arrays.toString(a)); 9: } 10: 11: public void print(Object a) { 12: System.out.println("O " + a); 13: } 14: 15: public void test() { 16: print(1); // 1st function is called 17: print(new int[] {1}); // The example of explicit 2nd function 18: print(); // 2nd function is called, but what is passed: NULL or empty array? 19: print(null); // 2nd function is called because it is less specific 20: print(1.2f); // 3rd function is called after float is boxed and widened 21: } 22: }
1: class Test1 { 2: 3: public void print(byte n1, byte n2) { 4: System.out.println("X " + n1 + n2); 5: } 6: 7: public void print(int n1, int n2) { 8: System.out.println("Y " + n1 + n2); 9: } 10: 11: public void test() { 12: print(1, 2); 13: } 14: }
1: class Test2 { 2: 3: public void print(float n1, float n2) { 4: System.out.println("X " + n1 + n2); 5: } 6: 7: public void print(double n1, double n2) { 8: System.out.println("Y " + n1 + n2); 9: } 10: 11: public void test() { 12: print(1, 2); 13: print(1.0, 2); 14: } 15: }
1: class Test3 { 2: 3: public void print(int n1, int n2) { 4: System.out.println("X " + n1 + n2); 5: } 6: 7: public void print(float n1, float n2) { 8: System.out.println("Y " + n1 + n2); 9: } 10: 11: public void print(double n1, double n2) { 12: System.out.println("Z " + n1 + n2); 13: } 14: 15: public void test() { 16: print(1l, 2); 17: } 18: }
Y 12 X 1.02.0 Y 1.02.0 Y 1.02.0
Same exercise with more scenarios:
1: class Test1 { 2: 3: public void print(byte n1, byte n2) { 4: System.out.println("X " + n1 + n2); 5: } 6: 7: public void print(int n1, int n2) { 8: System.out.println("Y " + n1 + n2); 9: } 10: 11: public void test() { 12: print(1, 2); // 2nd function is called 13: print((byte) 1, 2); // still 2nd function is called, as 1st argument is casted back to integer 14: print((byte) 1, (byte) 2); // now 1st function is called due to explicit cast 15: } 16: }
1: class Test2 { 2: 3: public void print(float n1, float n2) { 4: System.out.println("X " + n1 + n2); 5: } 6: 7: public void print(double n1, double n2) { 8: System.out.println("Y " + n1 + n2); 9: } 10: 11: public void test() { 12: print(1, 2); // 1st function is called, as float is the type of the minimal size to fit integer 13: print(1.0, 2); // 2nd function is called, because all numbers with floating point are treated as double 14: print((float) 1.0, 2); // 1st function is called and 2nd argument is automatically casted to float 15: print(1.0f, 2); // 1st function is called, as above 16: print((double) 1, (double) 2); // 2nd function is called due to explicit cast 17: print(1d, 2d); // 2nd function is called, as above 18: } 19: }
1: class Test3 { 2: 3: public void print(int n1, int n2) { 4: System.out.println("X " + n1 + n2); 5: } 6: 7: public void print(float n1, float n2) { 8: System.out.println("Y " + n1 + n2); 9: } 10: 11: public void print(double n1, double n2) { 12: System.out.println("Z " + n1 + n2); 13: } 14: 15: public void test() { 16: print(1l, 2); // 2nd function is called, as float is the type of the minimal size to fit integer 17: print(1, 2); // 1st function is called 18: print(1.0, 2); // 3rd function is called 19: } 20: }
public void power(Object n) { Integer b = (Integer) n; for (int i = 0; i < 5; i++) b *= b; // auto-unboxing, incrementing and auto-boxing (page 245) System.out.println("b=" + b); // What is the output? It will be 2^(2*2*2*2*2) = 2^32 = 0 } public void test() { power(2); // auto-boxing to Integer and widening to Object (page 252) }
Integer
variables are garbage collected at a particular point in this code? System.gc();
System.free();
null
public void amethod() { Integer i = new Integer(1); Integer j = new Integer(2); Integer k = new Integer(3); // insert here }
WeakReference
and SoftReference
in Java? WeakReference
and SoftReference
helps garbage collector and memory efficient, WeakReference
becomes eligible for garbage collection as soon as last strong reference is lost but SoftReference
even thought it can not prevent GC, it can delay it until JVM absolutely needs memory. In this respect SoftReference
suits best long-leaving caches (perhaps controlled by TTL), while WeakReference
is best for the data which can change in runtime:
ArrayIndexOutOfBoundsException
is thrown. What is the appropriate reaction? catch
block for ArrayIndexOutOfBoundsException
that prints out a descriptive message.throws ArrayIndexOutOfBoundsException
.ArrayIndexOutOfBoundsException
is a runtime exception, it indicates a faulty algorithm that should not be released. The only appropriate response is to find and fix the bug.
String
value starts the concatenation expression, Java automatically evaluates the result as concatenation of Strings
. What happens in following situation? What is the output? int m = 1, n = 2; String s = null; System.out.println(m + n + s); // OK or NullPointerException? System.out.println(s + m + n); // OK or NullPointerException?
3null null12
1: public class Test { 2: 3: public static Integer callMe() { 4: int a = 0; 5: return(++(a++)); // Compilation error: Invalid argument to operation ++/-- 6: } 7: 8: public static int runMe() { 9: int b = 0; 10: return(++b + b++); 11: } 12: 13: public static void main(String[] args) { 14: callMe() + 1; // Compilation error: The left-hand side of an assignment must be a variable 15: runMe()++; // Compilation error: Invalid argument to operation ++/-- 16: } 17: }
System.out.println(+~5);
-6
(~
is the bit inversion operator, and +
does not do anything)
See also what are bit operators good for.
int a[] = { 4, 5 }; int b = 1; a[b] = b = 0;
a = { 4, 0 }
This is because []
operator has highest precedence so it is evaluated first (see Java operator precedence table) and then assignment operator is evaluated from right-to-left: (a[0] = (b = 0))
.
Mind the |
and &
logical operators that evaluate both arguments.
Assertions are commonly used to check preconditions, postconditions, and class invariants.
A precondition is a constraint that must be met on entry of a method. If a method's preconditions are not met, the method should terminate at once before it can do any damage. A method's preconditions are typically functions of its arguments and the state of its object. Argument range checking at the start of a method is a common form of precondition testing.
A postcondition is a constraint that must be met on return from a method. If a method's postconditions are not met, the method should not be allowed to return. A method's postconditions are typically functions of its return value and the state of its object. In a general sense, if a precondition fails, the problem lies in the method's caller, whereas if a postcondition fails, the problem lies in the method itself.
A class invariant is a constraint on a class's state that must be met before and after execution of any non-private method of a class. Private methods might be used to restore the required state after execution of a non-private method.
public class Test { enum Format { JPEG, PNG, GIF // (1) Compilation error: ";" is missing at the end of enumeration list } public void process(Format format) { int i; if (format != null) { switch (format) { default: // (2) Compilation error: "default" statement should go last after all "case" statements i = 0; case Format.JPEG: // (3) Compilation error: The qualified case label Format.JPEG must be replaced with the unqualified enum constant JPEG i = 1; break; case Format.PNG: i = 2; break; } } System.out.println("i=" + i); // (4) Compile error: The local variable may not have been initialized } }
1: public class Test { 2: public void test(int i) { 3: outer : i++; 4: 5: if (i > 2) break outer; 6: 7: System.out.print(i + " "); 8: 9: test(i); 10: } 11: 12: public static void main(String[] args) { 13: new Test().test(0); 14: } 15: }
if
, for
, while
, do
or empty block) for example:
1: public class Test { 2: public void test(int i) { 3: outer : { 4: i++; 5: 6: if (i > 2) break outer; 7: 8: System.out.print(i + " "); 9: 10: test(i); 11: } 12: } 13: 14: public static void main(String[] args) { 15: new Test().test(0); 16: } 17: }
The above code will produce 1 2
.
1: for (int i = 7, long j = 0; i < 10; j++) { } 2: for (int i = 7, j = 0;; j++) { } 3: int j; for (int k = 0; j + k != 10; j++, k++) { } 4: int i; for (i++, int j = 0; i < 10; j++) { } 5: for (String s = ""; s.length() < 10; s += '!') { } 6: for (final String s : new String[]{"test"}) { } 7: int k; for (k: new int[]{1, 2, 3}) { }
Error
and RuntimeException
Let's assume that you have programmed the interface for your library:
import java.io.IOException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.xml.sax.SAXException; public interface XMLConfigurator { String getXMLConfigurationValue(String configurationName) throws ParserConfigurationException, SAXException, TransformerException, IOException; }
and some implementation:
import ...; public class XMLConfiguratorImpl implements XMLConfigurator { String getXMLConfigurationValue(String configurationName) throws ParserConfigurationException, SAXException, TransformerException, IOException { return ""; // in practise should do something sensible } }
but when somebody was using your library for example like below:
import ...; public class MainModule { XMLConfigurator xmlConfigurator = new XMLConfiguratorImpl(); public void readConfiguration() { String value; try { value = xmlConfigurator.getXMLConfigurationValue("color"); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (TransformerException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
he found out that exception handling was complicated to handle (a lot of catch
clauses). So you decided to change API to following:
import ...; public interface XMLConfigurator { String getXMLConfigurationValue(String configurationName) throws Exception; }
so now the exception handling looks much easier:
try { value = xmlConfigurator.getXMLConfigurationValue("color"); } catch (Exception e) { e.printStackTrace(); }
Questions:
XMLConfiguratorImpl
need any changes to confirm a new API?IOException
and other runtime exceptions, e.g. NullPointerException
. Better solution would be to introduce new exception that will wrap all others:
public interface XMLConfigurator { String getXMLConfigurationValue(String configurationName) throws XMLConfiguratorException; }
public void amethod() { outer : for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { System.out.println("i=" + i + " j= " + j); if (i > 0) break outer; } } System.out.println("Continuing with i set to =" + i); }
i=0 j= 0 i=0 j= 1 i=1 j= 0
i=0 j= 0 i=0 j= 1 i=1 j= 0 i=2 j= 0
i=0 j= 0 i=0 j= 1
i
variable is referred when it is out of scope.
StringBuilder
and StringBuffer
, Vector
and ArrayList
?
String
s are immutable and are stored in the string pool. What this means is that, once a String
is created, it stays in the pool in memory until being garbage collected. Therefore, even after you're done processing the string value (e.g., the password), it remains available in memory for an indeterminate period of time thereafter (again, until being garbage collected) which you have no real control over. Therefore, anyone having access to a memory dump can potentially extract the sensitive data and exploit it.
In contrast, if you use a mutable object like a character array, for example, to store the value, you can set it to blank once you are done with it with confidence that it will no longer be retained in memory.
String
. In other words, it will fail to account for code points outside of what is called the BMP, that is, code points with a value of U+10000
or greater.
The reason is historical: when Java was first defined, one of its goal was to treat all text as Unicode, but at that time Unicode did not define code points outside of the BMP. By the time Unicode defined such code points, it was too late for char to be changed.
This means that code points outside the BMP are represented with two chars in Java, in what is called a surrogate pair. Technically, a char in Java is a UTF-16 code unit.
The correct way to count the real numbers of characters within a String
, i.e. the number of code points, is either:
str.codePointCount(0, str.length())
or, with Java8:
str.codePoints().count()
char[] numbers = new char[] { '1', '2', '3' }; System.out.println(numbers + ""); System.out.println(numbers); System.out.println((Object) numbers);
PrintWriter#println(char x[])
(note that is only true for char[]
), the output will be similar to:
[C@3890c1ee 123 [C@3890c1ee
true
or false
? What are the conclusions? 1: import java.io.ByteArrayInputStream; 2: import java.io.ByteArrayOutputStream; 3: import java.io.IOException; 4: import java.io.ObjectInputStream; 5: import java.io.ObjectOutputStream; 6: import java.io.Serializable; 7: 8: public class Test { 9: 10: enum Type { 11: FATHER, MOTHER 12: } 13: 14: public static class Parent implements Serializable { 15: Parent parent; 16: Type type; 17: 18: public Parent(Type type) { 19: parent = this; 20: this.type = type; 21: } 22: } 23: 24: public static void main(String[] args) throws IOException, ClassNotFoundException { 25: Parent parent = new Parent(Type.MOTHER); 26: Parent parentClone; 27: 28: assert parent == parent.parent; // true or false? 29: 30: ByteArrayOutputStream bos = new ByteArrayOutputStream(); 31: 32: ObjectOutputStream os = new ObjectOutputStream(bos); 33: os.writeObject(parent); 34: os.close(); 35: 36: ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())); 37: parentClone = (Parent) is.readObject(); 38: is.close(); 39: 40: assert parent == parentClone; // true or false? 41: assert parent.parent == parentClone.parent; // true or false? 42: assert parentClone == parentClone.parent; // true or false? 43: assert parentClone.type == parent.type; // true or false? 44: } 45: }
true, false, false, true, true
. From above we can conclude, that deserialized objects are new instances in JVM (line 40). However the same instances in object graph (e.g. loops) are maintained (line 42). Also enums are unique within JVM (line 43).
==
operator. How JVM deals with serialization/deserialization of enum values (objects) to achieve this consistency?
See ObjectInputStream#readEnum(boolean)
, which uses T Enum#valueOf(Class<T> enumType, String name)
to support the consistency.
readObject()
/ writeObject()
are not a part of java.io.Serializable
interface to expose the API to serialization framework? What is java.io.Externalizable
interface for? Serializable
objects, thus impacting the security.
java.io.Externalizable
interface may be implemented by a class to have a control over serialization for all fields in class hierarchy, while using readObject()
/ writeObject()
the class can control the serialization of this class fields but parent(s) are processed in normal way (they may also implement these methods).
DataInputStream#readLine()
, RandomAccessFile#readLine()
, RandomAccessFile#readUTF()
, LineNumberReader#readLine()
, BufferedReader#readLine()
? DataInputStream#readLine()
and RandomAccessFile#readLine()
can be used to read 7-bit character (ASCII) strings as these methods are not Unicode-aware. With RandomAccessFile#readUTF()
one can read UTF-8 string but it should be prefixed with number of UTF-8 characters to read given as 2-byte short. LineNumberReader#readLine()
and BufferedReader#readLine()
do the character conversion, so they are the most correct way to read 8-bit strings (in native character set) or Unicode strings.
final Path path = Paths.get(...); Files.lines(path).forEach(System.out::println);
Files.lines()
is not closed. You should use:try ( final Stream<String> stream = Files.lines(path); ) { stream.forEach(System.out::println); }
Stream extends BaseStream
, and BaseStream
extends AutoCloseable
. While this has no influence on streams you obtain from collections for instance, the stream returned by Files.lines()
is I/O bound. Neglecting to close it correctly may lead to a resource leak in the event of an error occurring while processing the stream.
NumberFormat nf = NumberFormat.getInstance(); nf.setMaximumFractionDigits(3); System.out.println(nf.parse("222.5678")); System.out.println(nf.format(123.4687));
maximumFractionDigits
are only applicable for formatting the number as string, not for parsing. The number is rounded up to this limit when formatted:
222.5678 123.469
true
or false
? What are the conclusions? 1: import java.util.HashMap; 2: import java.util.Map; 3: 4: public class Test { 5: 6: public static void main(String[] args) { 7: Map<Number, String> m = new HashMap(); 8: 9: m.put(13, "super"); 10: 11: String s1 = "super"; 12: 13: m.put(13L, s1); 14: 15: String s2 = new String("super"); 16: 17: m.put((short) 13, s2); 18: 19: String s3 = new StringBuffer().append("super").toString(); 20: 21: m.put((byte) 13, s3); 22: 23: String t = m.get(13); 24: 25: assert m.size() == 4; // true or false? 26: assert "super" == t; // true or false? 27: assert m.get(13L) == t; // true or false? 28: assert m.get((short) 13) == t; // true or false? 29: assert m.get((byte) 13) == t; // true or false? 30: } 31: }
true, true, true, false, false
. From above we can conclude, that implementation of equals()
and hashCode()
methods treats numbers with the same “logical” value differently and result depends on class type (though it could have been implemented in Number
parent class). Also string pool has no impact on newly created String
object (lines 15 & 28) and StringBuffer
objects (lines 19 & 29). Also note widening to Object
after autoboxing in lines 9, 13, 17, 21, 23.
Enum.hashCode()
method implementation Enum.hashCode()
method implementation
1: public final int hashCode() { // note that the method is final and you can't override it 2: return super.hashCode(); 3: }
is replaced by the following:
1: public final int hashCode() { 2: return ordinal(); 3: }
Is it still a valid hashCode()
implementation? Is it better or worse hashCode()
implementation in comparison to original?
IllegalArgumentException
is thrown (see TreeMap$NavigableSubMap#put(K, V)
)
LinkedHashSet
and PriorityQueue
? PriorityQueue
is implementation of binary heap, i.e. it guarantees that lowest (or highest) priority element always remain at the head of the queue. This collection is unordered, e.g. elements may appear in the order different from how they have been added. In contrast iterator of LinkedHashSet
does guarantee the order on which elements are added.
Arrays#sort()
method for primitive type array with comparator?
Because there is no way to use primitives as class parametrization. In order to approach this challenge properly one need to create ComparableXXX
interface, Arrays.sort()
and Arrays.binarySearch()
methods for each primitive type.
Arrays#equals(Object[], Object[])
and Arrays#toString(Object[])
methods?
Because array objects do not override toString()
and equals()
methods, which are inherited from Object
and thus do not perform by element stringification / comparison.
Collection
interface has T[] toArray(T[])
method, but another overloaded version without argument (Object[] toArray()
) returns Object[]
?
Because of the type erasure there is no way to recover the parametrization class unless it is passed explicitly. Some implementations, like TypedList
can do this, because they store the target class as class instance variable.
1: public class Class<Class extends Serializable> { 2: Class Class; // Here "Class" is "this" Class or parametrization type or java.lang.Class? 3: 4: public Class(Class Class) { 5: this.Class = Class; 6: } 7: 8: java.lang.Class<?> getClass(Class Class) { 9: return Class.getClass(); 10: } 11: } 12: 13: class SuperClass extends Class<Number> { 14: 15: @Override 16: java.lang.Class<?> getClass(Integer Class) { 17: return super.getClass(Class); 18: } 19: }
Class
class does not have a default constructor. So SuperClass
should define a constructor that will invoke super one.SuperClass
intends to override the getClass(T)
method, but the signature should match exactly the parametrization type (getClass(Number)
and not getClass(Integer)
).See also Различные пространства имён.
1: public static <A extends Number> List<A> process1(List<A> nums) { 2: return nums; 3: } 4: 5: public static <A extends Number, B extends Number> List<A> process2(List<B> nums) { 6: return nums; // The return type does not match the passed parameter, as A is not the same as B. 7: } 8: 9: public static void test() { 10: List<Number> listN = null; 11: List<Integer> listI = null; 12: 13: listN = process1(listN); 14: listI = process1(listI); 15: 16: listI = process1(listN); // In this line and the next line there is an error, because List<Number> and List<Integer> are different collections, 17: listN = process1(listI); // which cannot be casted to each other, even though Integer is a Number. 18: 19: listN = process2(listN); 20: listI = process2(listI); 21: 22: listI = process2(listN); 23: listN = process2(listI); 24: }
Collection<? extends Number> c = new ArrayList<Long>(); ArrayList<Number> list = new ArrayList<Number>(); list.addAll(c);
c.add(Integer.valueOf(1))
is not allowed as given collection is homogeneous collection of one particular type.
public int compareTo(Object o) { Employee emp = (Employee) o; return this.id - emp.id; }
where id
is an integer number.
id
becomes negative than subtraction may overflow and produce an incorrect result. Correct implementation:public int compareTo(Object o) { Employee emp = (Employee) o; return (this.id < emp.id ) ? -1 : (this.id > emp.id) ? 1 : 0; }
Double
and BigDecimal
give equals() != (compareTo() == 0)
? java.lang.String
, but it's not mandatory. compareTo()
may be inconsistent to equals()
, which means compareTo()
may return zero, but object will not be equal by equals()
method. One of the prime example of this is java.math.BigDecimal
class, whose equals()
method return true if two BigDecimal
objects are equal in both value and scale e.g. 6.0 and 6.00 will not be equal, but compareTo()
will return zero given numbers are compared. For this reason BigDecimal
class can produce unexpected behaviour when stored in SortedSet
or SortedMap
.
See:
1: public class Test { 2: 3: public class Inner { 4: String caption; 5: 6: public Inner(String caption) { 7: this.caption = caption; 8: } 9: 10: public String toString() { 11: return "Caption: " + caption; 12: } 13: } 14: 15: public Inner test(String title) { 16: return new Inner("Main dialog") { 17: public String toString() { 18: return "Title: " + title; 19: } 20: }; 21: } 22: 23: public static void main(String[] args) { 24: System.out.println("Result: " + Test().test("Popup")); 25: } 26: }
Result: Title: Popup
after one fixes problem in line 18 (access to non-final variable title
) and line 24 (Test()
looks like a method call but should be a class instantiation: new Test().test(…)
).
1: public class Test { 2: 3: static class Parent { 4: private final String name; 5: 6: public Parent(String name) { 7: this.name = name; 8: } 9: 10: public String getName() { 11: return name; 12: } 13: } 14: 15: public static void main(String[] args) { 16: Test test = new Test(); 17: 18: test.print(test.new Parent("John") { 19: public String getName() { 20: return "Actual: " + super.getName(); 21: } 22: }); 23: } 24: 25: void print(Parent parent) { 26: System.out.println(parent.getName()); 27: } 28: }
static
modifier or change the instantiation to test.print(new Parent("John") ...
then the program produces Actual: John
.
1: public class Outer { 2: private int i; 3: 4: static class Inner<T extends Child> { 5: public void test(T o) { 6: Outer outer = o; 7: outer.i = 1; // Can "i" be accessed here? 8: outer.j = 2; // Can "j" be accessed here? 9: 10: Child child = o; 11: child.i = 3; // Can "i" be accessed here? 12: child.j = 4; // Can "j" be accessed here? 13: } 14: } 15: 16: public static void main(String[] args) { 17: new Outer.Inner().test(new Child()); 18: } 19: } 20: 21: class Child extends Outer { 22: private int j; 23: 24: public Child() { 25: super.i = 5; // Can "i" be accessed here? 26: } 27: }
true, false, false, false, false
. Check bug#7022052 for discussion concerning the problem of accessing the private variable from inner class in line 7: Java6 compiles this without error, but Java7 will raise a compile-time error (Java8 is fine with it again).
Unlike a synchronized statement, which triggers a mutex acquire, it will never suspend the calling thread or cause a context-switch. In addition to never blocking, atomic counters entirely avoid the OS interaction required by kernel-based mutex implementations. The locking is happening at extremely fine granularity – that of a single instruction – so the probability of contention is much lower.
Suspending a thread is a mechanism that allows any arbitrary thread to make another thread unready for an indefinite period of time. The suspended thread becomes ready when some other thread resumes it. This might feel like a useful technique, but it is very easy to cause deadlock in a program using these methods – a thread has no control over when it is suspended (the control comes from outside the thread) and it might be in a critical section, holding an object lock at the time. The exact effect of suspend()
and resume()
is much better implemented using wait()
and notify()
.
Thread.yield()
?
0 1 2 3
1 2 2 2
3 3 3 3
Sample
is an abstract class. It can't be instantiated.public class Sample extends Thread { public static void main(String argv[]) { System.out.print(Thread.currentThread().getId() + " "); Sample r = new Sample(); r.run(); } public void run() { for (int i = 0; i < 3; i++) System.out.print(Thread.currentThread().getId() + " "); } }
hp1
will execute; threads hp2
and hp3
will never get the CPU.hp1
will execute to completion, thread hp2
will execute to completion, then thread hp3
will execute to completion.hp1
, hp2
, and hp3
) will execute concurrently, taking time-sliced turns in the CPU.class HiPri extends Thread { HiPri() { setPriority(10); } public void run() { System.out.println("Another thread starting up."); while (true) { } } public static void main(String args[]) { HiPri hp1 = new HiPri(); HiPri hp2 = new HiPri(); HiPri hp3 = new HiPri(); hp1.start(); hp2.start(); hp3.start(); } }
InterruptedException
is not thrown by Thread.sleep()
.1: try { 2: Thread.sleep(100); 3: } catch (InterruptedException e) { }
aThread
and bThread
are both accessing a shared object named sharedOb
, and aThread
has just executed sharedOb.wait();
. What code can bThread
execute in order to guarantee to get aThread
out of the waiting state, no matter what other conditions prevail? aThread.notify();
aThread.notifyAll();
aThread.interrupt();
sharedOb.notify();
sharedOb.notifyAll();
InterruptedException
. (4) does not work because there might be multiple threads waiting for sharedOb
and only one of them will be notified.
Thread.UncaughtExceptionHandler
. Here's a simple example:
Thread otherThread = new Thread(); ... otherThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread th, Throwable ex) { System.out.println("Uncaught exception: " + ex); } }); otherThread.start();
RejectedExecutionException
if queue becomes full and no new workers can be spawned. The challenge is that ThreadPoolExecutor#execute(Runnable)
calls BlockingQueue#offer(E)
which according to contract should not block. The quick and dirty solution would be to turn that method into blocking:import java.util.concurrent.LinkedBlockingQueue; public class BoundedBlockingQueue<E> extends LinkedBlockingQueue<E> { public BoundedBlockingQueue(int maxSize) { super(maxSize); } @Override public boolean offer(E e) { // turn offer() and add() into a blocking calls (unless interrupted) try { put(e); return true; } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } return false; } } ... ExecutorService executorService = new ThreadPoolExecutor(threadsNumber, threadsNumber, 0L, TimeUnit.MILLISECONDS, new BoundedBlockingQueue(threadsNumber * 5));
Alternative way is to set rejection policy to one that executes the rejected job by a caller (it makes sense because the caller usually waits until all jos are executed):
import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
Future
which can be used to retrieve result from worker thread.
There is also a difference when looking at exception handling. If your task throws an exception and if it was submitted with execute()
this exception will go to the uncaught exception handler (when you haven't provided one explicitly1), the default one will just print the stack trace to System.err
). For a task that was submitted with submit()
and that terminates with an exception, the Future.get()
will re-throw this exception wrapped in an ExecutionException
.
Examples of mutex usage:
Examples of semaphore usage:
Comparison:
See also:
ReentrantLock
in Java:lockInterruptibly()
).tryLock()
) and ability to timeout while waiting for lock (tryLock(long time, TimeUnit unit)
).ReentrantLock(boolean fair)
). Fairness property provides lock to longest waiting thread, in case of contention.Collection<Thread> getQueuedThreads()
).
Disadvantages of
ReentrantLock
in Java:
finally
section, which makes code unreadable and hides business logic.
notify()
method was called and before the waiting thread woke up. That's why it always better to call wait()
method from loop, you can even create template for calling wait and notify in Eclipse.
int x = 0; boolean bExit = false;
Thread 1 (not synchronized):
x = 1; bExit = true;
Thread 2 (not synchronized):
if (bExit == true) System.out.println("x=" + x);
x=0
. Why? Because without any instruction to compiler e.g. synchronized or volatile, bExit=true
might come before x=1
in compiler reordering. Also, x=1
might not become visible in Thread 2, so Thread 2 will load x=0
. Now, how do you fix it?
One suggests to make both threads synchronized on a common mutex, another one said make both variables volatile
. Both are correct, as it will prevent reordering and guarantee visibility.
But the best answer is you just need to make bExit
as volatile
, then Thread 2 can only print x=1
. x
does not need to be volatile because x
cannot be reordered to come after bExit=true
when bExit
is volatile.
wait()
method is called thread releases the given object lock. But when sleep()
method is called from synchronized block or method, the thread doesn't release the lock that this thread holds.
volatile
keyword basically says to the JVM “Warning, this variable may be modified in another Thread”. In all versions of Java, the volatile
keyword guarantees global ordering on reads and writes to a variable. This implies that every thread accessing a volatile field will read the variable's current value instead of (potentially) using a cached value.
The volatile
keyword is also useful for 64-bit types like long and double since they are written in two operations. Without the volatile keyword you risk stale or invalid values.
In Java5 or later, volatile
modifier also helps to prevent reordering of code by compiler and volatile reads and writes establish a happens-before relationship, much like acquiring and releasing a mutex. Basically, Java Memory model inserts a write barrier after you write to a volatile variable and a read barrier before you read it. Which means, if you write to volatile field then its guaranteed that any thread accessing that variable will see the value you wrote.
Using volatile
may be faster than a lock, but it will not work in some situations. The range of situations in which volatile is effective was expanded in Java5; in particular, in double checked locking (DCL) of singleton class without volatile modifier it's possible for another thread in Java to see half initialized state of INSTANCE
variable, but with volatile variable guaranteeing happens-before relationship, all the write will happen on volatile INSTANCE
before any read of INSTANCE
variable. See Double-checked locking now works correctly.
volatile
makes reading / writing of the value consistent, but it does not make read+write operation atomic: l++
(long l
) can still be interrupted after the value was read but before it was written back. In that respect AtomicLong
behaves correctly.
One common example for using volatile
is for a flag to terminate a thread. If you've started a thread, and you want to be able to safely interrupt it from a different thread, you can have the thread periodically check a flag (i.e., to stop it, set the flag to true). By making the flag volatile, you can ensure that the thread that is checking its value will see that it has been set to true without even having to use a synchronized block. For example:
public class Foo extends Thread { private volatile boolean close = false; public void run() { while(!close) { // do work } } public void close() { close = true; // interrupt here if needed } }
See also When do you use volatile variables?.
Which of the following statements are true?
enum
is a keyword starting from Java6. enum
is a keyword starting from Java5.default
is a reserved word. true
is a literal. private
makes them protected from accidental corruption and improves encapsulation. this()
or super()
. this()
, and may use super()
only if it overrides the method from the parent class.final
method cannot be overloaded. final
method cannot be overridden, but overloading is fine.static final
method cannot be hidden. abstract
class must contain at least one abstract method. abstract
class must be extended. abstract
class may not have any final methods. final
class must contain at least one final method. java.lang.Object
. native
to access hardware that Java does not know about. private
modifier. name()
and toString()
of enum return its constant name. org/my company/module/Service.java
is a valid location for Java class in corresponding package. .class
output file after compilation. .class
file (like A$1.class
) will be created.ClassLoader
s. Outer.Inner i = Outer().new Inner();
Outer.Inner i = new Outer().new Inner();
new
operator is called from a function, the memory is allocated on the stack. new
operator always allocates the memory on heap.(x instanceof String[]) == (x != null && x.getClass().isArray() && x.getClass().getComponentType() == String.class)
s
to string pool, one need to call s.intern()
. String literal always refers to the same instance of class
String
, because string literals – or, more generally, strings that are the values of constant expressions, are “interned”.
java.io.Console#readPassword()
returns char[]
because String
is not secure as it can be interned and thus stay in memory uncontrolled long. String.substring()
may result a memory leak before Java7. String.substring()
created a new String instance that held the reference to parent character array (and kept start/end index in it), hence 1GB long string could not be freed just because e.g. 5 chars of it could be still referenced. In Java7 the new character array is always created, which solves the problem but results worth memory usage in case when the string and substrings are used, plus O(n)
complexity to create a substring.System.free()
will suggest the JVM to perform garbage collection. System.gc()
.Runtime.halt(int)
method executes shutdown hooks the same way as System.exit(int)
. double
can contain a 64-bit integer. double
precisely.int
type depends on underlying platform: for 32-bit platforms it is [-232 .. 232 - 1] and for 64-bit platforms it is [-264 .. 264 - 1]. int
type is fixed to range [-232 .. 232 - 1] and does not depend on the platform.myarray.length()
returns the number of elements in the given array. myarray.length
long microsPerDay = 24 * 60 * 60 * 1000 * 1000;
will correctly assign the number of microseconds in a day to the variable. long microsPerDay = 24L * 60 * 60 * 1000 * 1000;
System.out.println(myarray.toString());
will print all array elements to the screen. Arrays.toString(myarray);
otherwise you will see something like [Ljava.lang.Object;@64ab4d
on console.a[x][y] == a[x*sizeof(row) + y]
). Float a[] = {1.2};
is correct. double
so correct would be Float a[] = {1.2f};
or Double a[] = {1.2};
. Note that integer array elements a automatically downcasted to short
or byte
(with range checking): byte a[] = {1, 2};
.char a = '\u000A';
does not cause a compile-time error. 0x0A
(line feed) and 0x0D
(carriage return) as well as other unicode characters are interpreted literally as “end of line” and are processed very early in the translation process (at pre-compilation stage). So the compiler will trigger an error.0x5C
is backslash (\
), the following code System.out.println("\uuuuu005c"");
does not cause a compile-time error. u
symbols after slash are treated as one and escape unicode sequence is converted to character at pre-compiler stage. Thus compiler really sees System.out.println("\"");
String path = "map.txt"; // Taken from C:\cygwin\usr\share\map.txt
does not cause compile-time error. \usr
, even if it is placed in comment.short[] a = { 0 }; Cloneable c = a;
is a correct assignment. Cloneable
/ Serializable
interfaces and to Object
class.Byte a[] = null; Byte b[][] = null; boolean result = a == b;
is correct and results true
. new String() instanceof List
causes compile-time error. Math.ceil(Math.random() * 10)
always generates integer numbers from 1 to 10. [0..10)
, and the numbers will be float.byte b = 2
) and incrementing, subtraction, multiplication, division operators (e.g. b += 2
) are the only cases in Java when explicit casting is not necessary. ++
and --
do not perform promotion on their operands. +
expression when one of the operands is not primitive numeric type, a string or a literal, is illegal. String s = true + "";
is correct expression. Mind also the null
, true
, false
literals can only be added (or added to) a string.byte
is added to a char
, then the result type is short
. int
.i ^ i
always results 1 for any i
of type int
. byte
, short
, int
and, surprise, char
).int x = 6; x = ~x;
is a correct expression. -50 >> 1
is 25. >>
operator is a signed right shift, and shifting by one is the same as dividing by two.byte x = -1; x >>>= 5;
results a positive value in x
. x
has int
type. However in this case byte is widened to int
, non-signed shift takes place and the result is downcasted to byte
.-5 % 2
is 1
. -1
.ArithmeticException
is always raised by division operator when division by zero occurs (e.g. float a = 20.0f / 0
). Float.POSITIVE_INFINITY
(or analogous Double.POSITIVE_INFINITY
).ArithmeticException
can only be raised by division operator when division by zero occurs (e.g. int a = 5 / 0
). int a = 5 % 0
).0.1 * 3 == 0.3
x
, the most appropriate way to test for a NaN is if (x != x) ... // then x is NaN
. x
, x != Float.NaN
(and all comparison operators are false
– if you know SQL, this is very close to NULL
), but the most readable code is if (Float.isNaN(x)) ... // then x is NaN
.Integer.MIN_VALUE == -Integer.MIN_VALUE
Math.abs(Integer.MIN_VALUE) == Integer.MAX_VALUE
Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE
Math.min(Double.MIN_VALUE, 0.0d)
returns 0.0. Double.MIN_VALUE
is 2-1074 – a double constant whose magnitude is the least among all positive double values.x
is a class and the type of y
is an interface then the assignment x = y;
is never legal. x
is Object
and is not legal in all other cases.switch
statement may be of type long
. char
, byte
, short
, int
or enumeration type are allowed.for(;;) {}
causes the endless loop. for
-statement this way: for (int i = 0, int j = 0; i < 10 && j < 10; i++) ...;
for (int i = 0, j = 0; i < 10 && j < 10; i++) ...;
if (Boolean.valueOf("True")) { ... }
if
-statement should be either boolean
or Boolean
(unboxed).int x = 5; assert (x == 6) ? "x == 6" : "x != 6";
with result AssertionError
with message x != 6
. IllegalArgumentException
when conditions are not satisfied.printStackTrace()
method is called. printStackTrace()
method can be called from different place(s) in the code irrelevant to the place where the exception was raised.Long.valueOf(5).equals(5)
equals()
is auto-boxed to Integer
, which is not equal to Long
. However Integer.valueOf(1).equals(1)
is true.new Integer(0) == 0
. o1
and o2
are references to instances of java.lang.Object
. If (o1 == o2) == false
, then o1.equals(o2)
can be true
. Object#equals()
method which checks the object references. For other object types (different from java.lang.Object
) the above statement can be true.return (int) Math.random();
is a valid hashCode()
method implementation for any class. [0..1.0)
is always casted to 0 which does not violate the contract of hashcode function.Arrays.toString(Object[])
can deal with nested arrays and circular object references. Arrays.deepToString(Object[])
can deal with all above.Collections.order()
method. Collections.order()
method.Collections.sort()
method. Collections.sort()
for example, LinkedHashSet
is an ordered collection. For List
interface implementations the above statement is also false, as it will temporary sort the collection which will become unsorted in general case when a new element is added.Vector<Map> v;
is a correct Java5 declaration. Map
is not defined, this “mixture” is allowed in Java5.new TreeSet<Object>() {{ add(null); }};
does not cause NullPointerException
in Java6. null
into empty TreeSet
is acceptable but from Java7 onward it is non-acceptable (see bug#5045147). In Java6 it causes various side-effects as: add(null); add(obj);
causes NullPointerException
depending on whether obj.compareTo(Object)
is null-safe, add(null); remove(null);
also causes NullPointerException
.Stream
an Iterable
? Iterable<Object> iterable = Arrays.asList(...); StreamSupport.stream(iterable.spliterator(), false);
listOfOptionals.stream().flatMap(Optional::stream)...;
File dir = new File("."); dir.chDir("..");
will change to the directory above the current directory. chDir()
method. And there is no way to change the current directory in Java.StreamReader
class is designed to read characters from the stream (e.g. file or socket). BufferedInputStream#peak()
method can be used to get the next character from the stream without shifting the stream position forward. peak()
method in this class.OutputStreamWriter
must take a character encoding as a constructor parameter. InputStreamReader
may act as a constructor to OutputStreamReader
to convert between character sets. InputStreamReader
accepts only InputStream
as constructor argument.write()
operation. Socket#setSoTimeout()
sets it only for ServerSocket.accept()
, SocketInputStream.read()
and DatagramSocket.receive()
operations (see How to implement timeout for socket write() operation?).RandomAccessFile
must take a string mode parameter. rw
, r
, w
are valid mode parameters for RandomAccessFile
constructor. w
is not valid mode. However rws
(open for reading and writing with immediate updating of data and metadata changes) and rwd
(open for reading and writing with immediate updating of data but not metadata changes) are valid modes.OutputStreamWriter
is ASCII. file.encoding
system property.AutoCloseable
is an empty interface that extends Closeable
and marks resources that can participate in try-with-resources construction. Closeable
extends AutoCloseable
. The reason why AutoCloseable
was introduced is because there is a demand for close()
to throw any exception (for example, ResultSet
wants to throw SQLException
), see also Implement Closeable or AutoCloseable?JdbcRowSet
, JoinRowSet
, CachedRowSet
, FilteredRowSet
and WebRowSet
only CachedRowSet
is a disconnected row set. JdbcRowSet|
is connected RowSet
, rest of them are disconnected row sets, see Difference between Connected vs Disconnected RowSet in Java JDBC.private void readExternal()
method for that class. private Object readObject(java.io.ObjectInputStream in)
(if class implements Serializable
) or public void readExternal(java.io.ObjectInput in)
(if class implements Externalizable
).static
variables may not be transient
. static transient int a;
however static variables are anyway not serialized.Externalizable
interface for it to be correctly deserialized. Serializable
and does not implement Externalizable
, its nearest superclass that doesn't implement Serializable
must have a no-args constructor. public Animal clone() { return (Animal) super.clone(); }
is valid clone()
implementation of class Animal
that extends Object
. CloneNotSupportedException
must be dealt with.javax.crypto.SealedObject
. java.security.SignedObject
.Byte
class has readResolve()
method to enforce the flyweight pattern. wait()
/notify()
methods is better (recommended) way to block a thread than pause()
/suspend()
. pause()
/suspend()
are deprecated as may cause a deadlock (locks of the thread are not released when it is paused).start()
method is used to tell a suspended thread that it has the opportunity to run. start()
method is necessary to start a thread, but notify()
is used to tell a pool of threads waiting for lock release that one of them can run.Thread
or implement Runnable
. notify()
method on that thread. notify()
gives up the lock. notify()
and didn't exit the synchronized
block (e.g. sleeps for a while) still holds that lock and prevents other threads from being run (see Does notify/notifyall release the lock being held).obj
one need to call obj.wait()
. synchronized
modifier is enough to avoid concurrency issues with this class. Vector
methods are synchronized
, but still the class is not thread-safe and will throw IllegalModificationException
when one attempts to remove an element in one thread, while iterating over the elements in another.StringBuffer
is generally faster than StringBuilder
. StringBuffer
has all methods synchronized.String q; if (!(Optional.ofNullable(q).filter(s -> !s.trim().isEmpty())).isPresent()) { ... }
is equivalent to if (org.apache.commons.lang3.StringUtils.isBlank(q)) { ... }
if (StringUtils.isNotBlank(q)) { … }
List<String> list = ...; if (Optional.ofNullable(list).orElseGet(() -> new ArrayList<String>()).size() == 0) { ... }
is equivalent to if (org.apache.commons.collections4.CollectionUtils.isEmpty(list)) { ... }
javax.xml.xpath.XPath#evaluate(String expression, Object item)
org.w3c.dom.Node
and in order to pass XML one need to call xpath.evaluate(new org.sax.xml.InputSource(xmlString))
.Thread
gives you access to more functionality of the Java threading capability than implementing the Runnable
interface. setPriority()
method. main()
. public static <T> List<Future<T>> invokeAll(Stream<Callable<T>> tasks) { ... }'' the expression ''invokeAll(ids.map((id) -> () -> id));
is correct.
Array elements are always, always, always given default values, regardless of where the array itself is declared or instantiated.
declared should be read as defined. Imagine the code int[] a;
that declares the array a
which is not given the default values, while the code int[] a = {0};
declares and defines the array a
.
getBidValue()
function is not defined in line 12. The code in answers section differs from one in questions on page 272, which is correct.… both operands are fully evaluated before the operator is applied.
however these operators have only one operand (+=
and family are called “assignment operators”).
String[] files = new String[100];
. The same in chapter 7 on page 587: TreeSet<Integer> subset = new TreeSet<Integer>(); subset = (TreeSet) times.headSet(1600);
Only variables and methods may be declared protected.
Of course, the authors of the book have not introduced the inner classes by that moment, but for the sake of complicity I won't make statements like that.
A private method may be overridden by a private, default, protected, or public method.
I think, that we can speak only about re-declaration of a private method, as overriding assumes that we can call a parent method (super()
) which is impossible for private methods (see question regarding overriding and overloading static methods).
int i = 12; byte b = I
should be read as:
int i = 12; byte b = i;
E. Any type, including classes with any kind of modifier, may appear inside the parentheses of a cast.
however the test does not have this option (see page 125): Which of the following may legally appear as the new type (between the parentheses) in a cast operation? A. Abstract classes B. Final classes C. Primitives D. All of the above
int j = 0; for (int k=0, j+k != 10; j++,k++) { System.out.println("j=" + j + ", k=" + k); }
but should be
... for (int k=0; j+k != 10; j++,k++) { ...
otherwise it does not compile (and can't be the right answer).
Consider the following code:
1. public class Assertification { 2. public static void main(String[] args) { 3. assert args.length == 0; 4. } 5. }Which of the following conditions must be true in order for the code to throw an AssertionError? Assume you are using release 5.0. (Choose all that apply.) A. The source code must be compiled with the -source 1.5 flag. …
and the answer on page 165 is A, B, D
, while the explanation contradicts with answer (I suppose it should be B, D
):
A, B, D. … 5.0 does not require a
-source
flag. So A is not a requirement.
17. add( 18. new Button("Hello " + 1) { 19. // initializer 20. addActionListener( 21. new ActionListener() {
should read:
17. add( 18. new Button("Hello " + 1) { 19. { // initializer 20. addActionListener( 21. new ActionListener() {
otherwise it does not compile.
A
is illegal because the list of names must be terminated by a semicolon.
which is false statement: the semicolon at the end of list is optional. The corresponding prove is on page 207:
10. Which of the following are legal enums? A. enum Animals { LION, TIGER, BEAR } …
A. An anonymous inner class must appear inside a block of code.
I am not completely agreed with this statement. Consider the code below:
import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class Test { private MouseAdapter adapter = new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { super.mouseClicked(e); } }; }
This code creates an anonymous class not in code section, but in class member declaration section. However, technically this code is transformed into:
import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class Test { private MouseAdapter adapter; { adapter = new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { super.mouseClicked(e); } }; } }
which correlates with the statement, but my position is still the same.
A monitor is an instance of any class that has synchronized code.
I disagree. The more correct is just to say: “A monitor can be an instance of any class”. Consider the following example:
public class Test { public void doJob() { int a = 1; synchronized (Boolean.TRUE) { a++; } } }
What is the monitor in this case: instance of class Test
(that has synchronized code) or instance of class Boolean
?
%b Formats a boolean value (wrapper or primitive)
Well, you can't pass the primitive to Formatter#format()
as varargs are always passed as objects.
;
on line 8.A. Which statements are true?
is wrongly labelled.E. .start()
not actually an answer, but a part of previous line."Девица не хочет лезть в Окно" – device not compatible with Windows.