Rompecabezas Joker 2018



Aloha!

Entonces, una de las conferencias m谩s intensas en el mundo de Java: Joker 2018, que tradicionalmente tiene lugar en San Petersburgo en el Expoforum, ha terminado. Este a帽o asistieron a la conferencia un n煤mero r茅cord de participantes. Odnoklassniki tradicionalmente se ofrece para ayudar a nuestros desarrolladores a resolver problemas no triviales que surgen al crear uno de los proyectos Java m谩s cargados.

Los que respondieron bien las preguntas recibieron premios, y les ofrecemos un breve an谩lisis de nuestros problemas. Ocultamos las respuestas correctas debajo del spoiler, chur, para abrir solo despu茅s de que nosotros mismos descubrimos la soluci贸n ;-)

Vamos!

Deduplicador


Cyril quiere ahorrar memoria deduplicando objetos iguales en equals() . Ay煤delo a implementar el m茅todo de deduplicaci贸n segura para subprocesos por analog铆a con String.intern , pero no solo para cadenas.

 public static Object dedup(Object obj) { } 

Soluci贸n
Despu茅s de rascarse la parte posterior de la cabeza, Cyril pudo idear varias opciones para resolver este problema, pero de alguna manera todos estaban equivocados. Luego, rasc谩ndose la nariz y el muelle sobre java.util.concurrent , record贸 el maravilloso m茅todo computeIfAbsent . Este m茅todo ejecutar谩 la lambda que se le pasa en el par谩metro solo si no hay una clave en el Map , escribe su resultado y devuelve. Si tal clave ya existe, lambda no se calcular谩 y se devolver谩 el valor actual asociado con la clave. Adem谩s, record贸 Kirill, para ConcurrentHashMap este m茅todo funciona at贸micamente, lo que le permite resolver el problema con mucha elegancia. Cirilo satisfecho escribi贸 este c贸digo:

 private static final ConcurrentHashMap map = new ConcurrentHashMap(); public static Object dedup(Object obj) { return map.computeIfAbsent(obj, o -> o); } 

y con gusto se rasc贸 la nariz otra vez.

Direcci贸n IP


Dima est谩 desarrollando un nuevo protocolo de red. Corrija el error en su m茅todo para traducir una direcci贸n IPv4 representada como una matriz de bytes en una cadena.

 String ipToString(byte[] ip) { return ip[0] + '.' + ip[1] + '.' + ip[2] + '.' + ip[3]; } 

Soluci贸n
El primer error fue mostrado inmediatamente por el IDE, evitando que Dima incluso agregue el m茅todo al final. El s铆mbolo '.' tener tipo char se agrega al byte como un tipo entero. Reemplazando '.' a "." , Dima estaba tan contento con el c贸digo compilado con 茅xito que lo lanz贸 inmediatamente sin probarlo. "Ay-ah-ah, Dima", pens贸 la JVM y dio algunas tonter铆as en lugar de la direcci贸n IP. A diferencia de Dima, la JVM sab铆a con certeza que en Java, el tipo de byte se usa para almacenar n煤meros con signo, es decir, todas las direcciones con octetos mayores que 127 estar谩n representadas por n煤meros negativos en Java. Seg煤n las reglas de emitir estos n煤meros a int , el signo negativo del n煤mero es el mismo que en el byte original. Ah, Dmitry, era necesario tomar medidas adicionales para descartar la parte del letrero, por ejemplo, as铆:

 return (ip[0] & 255) + "." + (ip[1] & 255) + "." + (ip[2] & 255) + "." + (ip[3] & 255); 


Mezclador


Marina necesita mezclar los elementos de la lista en orden aleatorio. 驴Por qu茅 esta opci贸n no es adecuada y c贸mo la solucionar铆a?

 Random random = ThreadLocalRandom.current(); list.sort((o1, o2) -> { return random.nextBoolean() ? +1 : -1; }); 

Soluci贸n
Marina, obviamente, olvid贸 que el contrato del Comparator requiere estabilidad: al comparar dos valores id茅nticos, el resultado de la comparaci贸n deber铆a ser el mismo. Y en la implementaci贸n de Marina, el resultado para cada par es estrictamente aleatorio, lo que puede conducir f谩cilmente a una excepci贸n java.lang.IllegalArgumentException: Comparison method violates its general contract ! Si Marina le铆a la documentaci贸n por las tardes, sabr铆a que en este caso es mejor usar el m茅todo Collections.shuffle() .

Respuesta: se viola el contrato de comparaci贸n. La clasificaci贸n puede arrojar una excepci贸n. Es mejor usar el m茅todo Collections.shuffle() .

Bel茅n funcional


A Egor le encanta escribir en un estilo funcional, sin preocuparse por la efectividad del c贸digo. 驴Estime cu谩ntos objetos crea cada llamada a este m茅todo si se le pasa una ArrayList de 10 l铆neas?

 Predicate<String> equalsAny(List<String> list) { Predicate<String> p = s -> false; for (String s : list) { p = p.or(s::contains); } return p; } 

Soluci贸n
A diferencia de Yegor, a la pedante Alina no le gusta escribir todo en un estilo funcional, porque sabe c贸mo calcular los costos generales. L铆nea 煤nica

p = p.or(s::contains);

Crea dos objetos a la vez: uno como resultado de llamar a p.or() , y el segundo para crear el predicado s::contains . Este 煤ltimo no se puede almacenar en cach茅 ya que captura la variable s en el contexto. Multiplicando por el n煤mero de iteraciones, obtenemos 20 objetos. Pero tambi茅n se puede crear un Iterator oculto si el JIT no lo optimiza. "20 o incluso 21 objetos, si no tienes suerte, es un pecador", pens贸 Alina.

Respuesta: 10 predicados or + 10 predicados contains + 1 Iterator dependiendo de las optimizaciones JIT.

Maxim se enciende al m谩ximo


Maxim calcula el m谩ximo en un programa multiproceso, pero quiere prescindir de bloqueos. Ay煤dale a arreglar el error.

 AtomicLong max = new AtomicLong(); void addValue(long v) { if (v > max.get()) { max.set(v); } } 

Soluci贸n
Oh Maxim! El uso de AtomicLong no hace que el programa sea seguro. Hay una operaci贸n at贸mica AtomicLong.compareAndSwap . Y comenzando con Java 8, no es necesario escribir el ciclo CAS usted mismo, porque accumulateAndGet el maravilloso m茅todo at贸mico accumulateAndGet . Y aqu铆 es conveniente usarlo solo:

 void addValue(long v) { max.accumulateAndGet(v, Math::max); } 

Source: https://habr.com/ru/post/es427337/


All Articles