Hints how to enable code re-alignment (from How to debug compiled Java code in Eclipse):
java.util.Stack
? java.util.Stack
is known to be based on java.util.Vector
and thus is slow. What are the faster alternatives?
Use java.util.Deque
interface implementations (push()
, peek()
and remove()
operations). java.util.ArrayDeque
does not support null
elements in contrast to java.util.LinkedList
. Apache org.apache.commons.collections.ArrayStack
is better then java.util.ArrayDeque
, but it is not generalized (check Using generics with commons collections).
List#subList(int fromIndex, int toIndex)
ListUtils#partition(List<T> list, int size
also works in effective way and is based on List#subList(int, int)
:
import org.apache.commons.collections4.ListUtils; List<List<?>> chunkedList = ListUtils.partition(sourceList, chunkSize);
java.util.Enumeration
instance? import org.apache.commons.collections4.FluentIterable; Enumeration e = FluentIterable.<String> empty().asEnumeration();
import org.apache.commons.collections4.IteratorUtils; Enumeration e = IteratorUtils.asEnumeration(Collections.emptyListIterator());
import org.springframework.util.AntPathMatcher; new AntPathMatcher().match(pattern, path); // e.g. match("/**/user/*", "/global/user/12");
?q=word+word
should become ?q=word%2bword
.
+
is a special character as to RFC 2396 it does not need to be escaped. For example, consider query ?key+=+val
which is interpreted as ?key = val
at server side and that is perhaps the desired effect. Other builders work on higher semantic level (one can pass query parameter name and value separately), thus can do smarter escaping (at least to control it). Nevertheless they could have different views on what should be escaped:import org.springframework.web.util.UriComponentsBuilder; import javax.ws.rs.core.UriBuilder; System.out.println(UriComponentsBuilder.fromHttpUrl("http://host.com/path").queryParam("q", "my+zip%20/?&").build().encode().toUri()); System.out.println(UriComponentsBuilder.fromHttpUrl("http://host.com/path{suffix}").path("{sub}").queryParam("q", "{value}").buildAndExpand("/group%31?", "/id%41?", "my+zip%20/?&").encode().toUri()); System.out.println(); System.out.println(UriBuilder.fromUri("http://host.com/path").queryParam("q", "my+zip%20/?&").build()); System.out.println(UriBuilder.fromUri("http://host.com/path{suffix}").path("{sub}").queryParam("q", "{value}").build("/group%31?", "/id%41?", "my+zip%20/?&"));
produces output:
http://host.com/path?q=my%2Bzip%2520/?%26 http://host.com/path/group%2531%3F/id%2541%3F?q=my%2Bzip%2520/?%26 http://host.com/path?q=my%2Bzip%20%2F?%26 http://host.com/path%2Fgroup%2531%3F/%2Fid%2541%3F?q=my%2Bzip%2520%2F?%26
write()
operation? Thread#interrupt()
on a blocked in the read thread has no effect (see Interrupting a thread that waits on a blocking action?).
The solution is either launch a separate thread as watchdog or use non-blocking I/O: register selector for OP_WRITE
events and select with timeout.
import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Iterator; final long WRITE_TIMEOUT_MS = 2000; // 2 seconds SocketChannel channel = SocketChannel.open(); Selector selector = Selector.open(); channel.connect(new InetSocketAddress()); channel.configureBlocking(false); // switch to non-blocking after connection has succeeded channel.register(selector, SelectionKey.OP_WRITE); while (true) { int readyChannels = selector.select(WRITE_TIMEOUT_MS); if (readyChannels == 0) { continue; } for (Iterator<SelectionKey> iter = selector.selectedKeys().iterator(); iter.hasNext();) { SelectionKey key = iter.next(); if (key.isValid() && key.isWritable()) { // a channel is ready for writing channel.write(buffer); } // remove the key thus marking it as processed: iter.remove(); } }
HttpURLConnection
returns body input stream via URLConnection#getInputStream()
if HTTP response code was 2xx or 3xx, and HttpURLConnection#getErrorStream()
otherwise.getInputStream()
can throw the exception which was remembered during negotiation phase.
docs/api/java/net/HttpURLConnection.html#HttpURLConnection#setFixedLengthStreamingMode%28int%29
), which results an exception when trying to read or write a body.
Origin
or Content-Length
cannot be set on java.net.HttpURLConnection
connection.setRequestProperty("Origin", "localhost");
it has no effect.
-Dsun.net.http.allowRestrictedHeaders=true
Library | Can read/unmarshall multipart message | Can create / marshall multipart message |
---|---|---|
Apache mime4j | ![]() | ![]() |
Apache HTTP client | ![]() | ![]() |
Apache FileUpload | ![]() | ![]() |
Spring | ![]() | ![]() MultipartHttpMessageWriter ) |
Sending the message from prepared message template:
--SgkN_pfgxWH2sRuHgygqYkEQgctzP9HK0s5 Content-Disposition: form-data; filename="text-part" Content-Type: text/plain; charset=UTF-8 This is a message! --SgkN_pfgxWH2sRuHgygqYkEQgctzP9HK0s5--
import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import org.apache.commons.io.IOUtils; private void requestMultipartRestTemplate() throws URISyntaxException, IOException { RestTemplate restTemplate = new RestTemplate(); byte[] message = IOUtils.toByteArray(getClass().getClassLoader().getResourceAsStream("multipart.txt")); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add(HttpHeaders.CONTENT_TYPE, "multipart/form-data; boundary=SgkN_pfgxWH2sRuHgygqYkEQgctzP9HK0s5"); httpHeaders.setContentLength(message.length); httpHeaders.setAccept(Collections.singletonList(MediaType.MULTIPART_FORM_DATA)); ResponseEntity<byte[]> httpResponse = restTemplate.postForEntity( new URI("http://host.com/path"), new HttpEntity<>(message, httpHeaders), byte[].class); System.out.println(httpResponse.getStatusCode()); System.out.println(IOUtils.toString(httpResponse.getBody(), "UTF-8")); }
import org.springframework.http.HttpHeaders; import org.apache.commons.io.IOUtils; private static void requestMultipartURLConnection() throws URISyntaxException, IOException { byte[] message = IOUtils.toByteArray(getClass().getClassLoader().getResourceAsStream("multipart.txt")); HttpURLConnection connection = (HttpURLConnection) new URL("http://host.com/path").openConnection(); connection.setRequestMethod("POST"); connection.setDoOutput(true); connection.setRequestProperty(HttpHeaders.CONTENT_TYPE, "multipart/form-data; boundary=SgkN_pfgxWH2sRuHgygqYkEQgctzP9HK0s5"); connection.setRequestProperty(HttpHeaders.CONTENT_LENGTH, Integer.toString(message.length)); try (OutputStream os = connection.getOutputStream()) { IOUtils.write(message, os); } System.out.println(connection.getResponseCode() + " " + connection.getResponseMessage()); InputStream is = null; try { is = connection.getErrorStream(); if (is == null) { is = connection.getInputStream(); } System.out.println(IOUtils.toString(is, "UTF-8")); } finally { IOUtils.closeQuietly(is); } }
Constructing and sending the message on the fly using Apache HTTP client:
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.commons.io.IOUtils; private static void requestMultipartApacheClient() throws URISyntaxException, IOException { HttpPost httpPost = new HttpPost("http://host.com/path"); MultipartEntityBuilder multipartBuilder = MultipartEntityBuilder.create(); httpPost.setEntity(multipartBuilder.addTextBody("text-part", "This is a message!", ContentType.TEXT_PLAIN).build()); CloseableHttpClient httpClient = HttpClientBuilder.create().build(); CloseableHttpResponse httpResponse = httpClient.execute(httpPost); System.out.println(httpResponse.getStatusLine()); System.out.println(IOUtils.toString(httpResponse.getEntity().getContent(), StandardCharsets.UTF_8)); }
Receiving using Apache FileUpload:
import org.apache.commons.fileupload.MultipartStream; import org.apache.commons.lang3.ObjectUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpInputMessage; import org.springframework.http.MediaType; import org.springframework.util.Assert; private static final Pattern CONTENT_TYPE_HEADER = Pattern.compile(HttpHeaders.CONTENT_TYPE + ":\\s*([^\r\n]+)", Pattern.CASE_INSENSITIVE); static class StringMultipart extends ArrayList<String> { } private static StringMultipart readMultipart(HttpInputMessage inputMessage) throws IOException { String boundary = inputMessage.getHeaders().getContentType().getParameter("boundary"); Assert.notNull(boundary, "boundary parameter should be specified"); ArrayList<String> result = new ArrayList<>(); try (InputStream is = inputMessage.getBody(); ByteArrayOutputStream baos = new ByteArrayOutputStream()) { MultipartStream multipartStream = new MultipartStream(is, boundary.getBytes(StandardCharsets.US_ASCII)); multipartStream.setHeaderEncoding(StandardCharsets.US_ASCII.toString()); boolean nextPart = multipartStream.skipPreamble(); while (nextPart) { String headers = multipartStream.readHeaders(); Matcher headerMatcher = CONTENT_TYPE_HEADER.matcher(headers); Charset bodyCharset = ObjectUtils.defaultIfNull( headerMatcher.find() ? MediaType.parseMediaType(headerMatcher.group(1)).getCharset() : null, StandardCharsets.UTF_8); multipartStream.readBodyData(baos); result.add(baos.toString(bodyCharset.toString())); baos.reset(); nextPart = multipartStream.readBoundary(); } } return result; }
Sending/receiving using Apache mime4j:
import org.apache.james.mime4j.dom.Message; import org.apache.james.mime4j.dom.Multipart; import org.apache.james.mime4j.field.Fields; import org.apache.james.mime4j.message.BodyPartBuilder; import org.apache.james.mime4j.message.DefaultMessageWriter; import org.apache.james.mime4j.message.MultipartBuilder; import org.apache.james.mime4j.stream.EntityState; import org.apache.james.mime4j.stream.Field; import org.apache.james.mime4j.stream.MimeTokenStream; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.MimeType; import org.springframework.web.client.RestTemplate; public void requestMultipartApacheMime4jSpring() throws IOException { Multipart multipart = MultipartBuilder.create().setSubType("form-data") .addBodyPart(BodyPartBuilder.create().setBody("This is a message!", StandardCharsets.UTF_8) .setField(Fields.contentType("text/plain; charset=UTF-8")) .setContentDisposition("form-data", "text-part").build()) .build(); Message message = Message.Builder.of().setBody(multipart).build(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); new DefaultMessageWriter().writeBody(message.getBody(), bos); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentLength(bos.size()); httpHeaders.setAccept(Collections.singletonList(MediaType.MULTIPART_FORM_DATA)); for (Field field : message.getHeader()) { httpHeaders.add(field.getName(), field.getBody()); } System.out.println(httpHeaders.toString()); System.out.println(new String(bos.toByteArray(), StandardCharsets.UTF_8)); ResponseEntity<byte[]> responseEntity = new RestTemplate().postForEntity( "http://host.com/path", new HttpEntity<>(bos.toByteArray(), httpHeaders), byte[].class); MimeTokenStream mimeTokenStream = new MimeTokenStream(); mimeTokenStream.parseHeadless(new ByteArrayInputStream(responseEntity.getBody()), responseEntity.getHeaders().getContentType().toString()); do { if (mimeTokenStream.getState() == EntityState.T_BODY) { System.out.println(IOUtils.toString(mimeTokenStream.getInputStream(), ObjectUtils.defaultIfNull(MimeType .valueOf(mimeTokenStream.getBodyDescriptor().getMimeType()).getCharset(), StandardCharsets.UTF_8))); } } while (mimeTokenStream.next() != EntityState.T_END_OF_STREAM); }
select()
mechanism (implement java.nio.channels.SelectableChannel
), and java.nio.channels.AsynchronousFileChannel
supports non-blocking I/O using java.util.concurrent.Future
interface.
Runtime.exec("mkfifo")
in Linux or using JNA in Windows. Consuming the existing pipe is done in usual way:FileInputStream pipeStream = new FileInputStream("\\\\.\\pipe\\my_pipe"); ... pipeStream.close();
java.io.tmpdir
system variable from TMP
or TEMP
environment variable for any OS except Windows (see Environment variable to control ''java.io.tmpdir''). So to be compatible pass -Djava.io.tmpdir=/work
to your JDK.
taskkill /t
will not terminate Java process started by start /b
. And taskkill /f
will kill the process without letting shutdown hooks to run.
As Maven artifacts for JAI are brocken, use alternative / clones:
String#intern()
the Java allocates the memory on the PermGen space. If you have a very heavy application with tons of classes, the classes are competing with the interned strings on the space. While the GC does clean up the permgen space (at least on Sun JDK), it does it only in a “stop the world” GC and not in a CMS which you typically configure your webapp or desktop to. Bottom line: items in the intern pool can be GC'd, but it's complex and unusual.
Interners
class is an alternative implementation of String#intern().
org.apache.commons.lang.NotImplementedException
and java.lang.UnsupportedOperationException
? Bicycle.drive(fish)
).
See also Restore NotImplementedException and UnhandledException.
Range
API in Apache Commons Lang and Ranges
in Guava Collections (see Ranges in Java, what's the best approach?). If that API is not enough, you need Interval tree implementation (see Data structure for quick interval look up, IntervalTree Java implementation, Interval Tree Java Implementation).
See also:
/** * Get the value of private field {@code fieldName} of given object {@code target}. */ public static <T> T getPrivateField(Object target, String fieldName) { try { return getPrivateField(target, target.getClass(), fieldName); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } } /** * Get the value of private field {@code fieldName} of given object {@code target} which is treated as class * {@code clazz}. * * @throws NoSuchFieldException * if given field was not found */ @SuppressWarnings("unchecked") private static <T> T getPrivateField(Object target, Class<?> clazz, String fieldName) throws NoSuchFieldException { try { Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); return (T) field.get(target); } catch (NoSuchFieldException e) { if (clazz.getSuperclass() == Object.class) { // Field is really not found: throw e; } // Try super class: return getPrivateField(target, clazz.getSuperclass(), fieldName); } catch (IllegalAccessException e) { throw new RuntimeException(e); } }
The same, but using Spring utility methods:
import org.springframework.util.ReflectionUtils; /** * Get the value of private field {@code fieldName} of given object {@code target}. */ @SuppressWarnings("unchecked") public static <T> T getField(Object target, String fieldName) { Field field = ReflectionUtils.findField(target.getClass(), fieldName); ReflectionUtils.makeAccessible(field); return (T) ReflectionUtils.getField(field, target); }
The same, but using Apache Commons Lang utility methods:
import org.apache.commons.lang3.reflect.FieldUtils; /** * Get the value of private field {@code fieldName} of given object {@code target}. */ @SuppressWarnings("unchecked") public static <T> T getField(Object target, String fieldName) { try { return (T) FieldUtils.readField(target, fieldName, true); } catch (IllegalAccessException e) { throw new RuntimeException(e); } }
public int sumFromOneToN(int n) { if (n < 1) { return 0; } return n + sumFromOneToN(n - 1); }
Tail recursion occurs when the recursive call is in the tail position within its enclosing context – after the function calls itself, it performs no additional work. That is, once the base case is complete, the solution is apparent. For example:
public int sumFromOneToN(int n, int a) { if (n < 1) { return a; } return sumFromOneToN(n - 1, a + n); }
Here you can see that a plays the role of the accumulator – instead of computing the sum on the way down the stack, we compute it on the way up, effectively making the return trip unnecessary, since it stores no additional state and performs no further computation. Once we hit the base case, the work is done – below is that same function, “unrolled”.
public int sumFromOneToN(int n) { int a = 0; while(n > 0) { a += n--; } return a; }
Another example of not tail recursion (classical):
int factorial(int n) { return (n == 0) ? 1 : n * factorial(n - 1); }
int fac_times(int n, int acc) { return (n == 0) ? acc : fac_times(n - 1, acc * n); } int factorial(int n) { return fac_times(n, 1); }
Many functional languages natively support tail call optimization, however JVM does not. In order to implement recursive functions in Java, we need to be aware of this limitation to avoid StackOverflowErrors. In Java, iteration is almost universally preferred to recursion.
"Девица не хочет лезть в Окно" – device not compatible with Windows.